<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=2">
<meta name="theme-color" content="#222">
<meta name="generator" content="Hexo 6.3.0">
  <link rel="apple-touch-icon" sizes="180x180" href="/images/favicon.ico">
  <link rel="icon" type="image/png" sizes="32x32" href="/images/favicon.ico">
  <link rel="icon" type="image/png" sizes="16x16" href="/images/favicon.ico">
  <link rel="mask-icon" href="/images/favicon.ico" color="#222">

<link rel="stylesheet" href="/css/main.css">


<link rel="stylesheet" href="/lib/font-awesome/css/all.min.css">
  <link rel="stylesheet" href="//cdn.jsdelivr.net/gh/fancyapps/fancybox@3/dist/jquery.fancybox.min.css">

<script id="hexo-configurations">
    var NexT = window.NexT || {};
    var CONFIG = {"hostname":"daorongxing.gitee.io","root":"/","scheme":"Gemini","version":"7.8.0","exturl":false,"sidebar":{"position":"left","display":"post","padding":18,"offset":12,"onmobile":false},"copycode":{"enable":true,"show_result":true,"style":"mac"},"back2top":{"enable":true,"sidebar":true,"scrollpercent":true},"bookmark":{"enable":false,"color":"#222","save":"auto"},"fancybox":true,"mediumzoom":false,"lazyload":false,"pangu":true,"comments":{"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},"algolia":{"hits":{"per_page":10},"labels":{"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}},"localsearch":{"enable":true,"trigger":"auto","top_n_per_article":1,"unescape":false,"preload":false},"motion":{"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}},"path":"search.xml"};
  </script>

  <meta name="description" content="这是我的个人博客，记录计算机学习之路！">
<meta property="og:type" content="website">
<meta property="og:title" content="邢道荣的个人博客">
<meta property="og:url" content="https://daorongxing.gitee.io/index.html">
<meta property="og:site_name" content="邢道荣的个人博客">
<meta property="og:description" content="这是我的个人博客，记录计算机学习之路！">
<meta property="og:locale" content="zh_CN">
<meta property="article:author" content="Daorong Xing">
<meta name="twitter:card" content="summary">

<link rel="canonical" href="https://daorongxing.gitee.io/">


<script id="page-configurations">
  // https://hexo.io/docs/variables.html
  CONFIG.page = {
    sidebar: "",
    isHome : true,
    isPost : false,
    lang   : 'zh-CN'
  };
</script>

  <title>邢道荣的个人博客</title>
  






  <noscript>
  <style>
  .use-motion .brand,
  .use-motion .menu-item,
  .sidebar-inner,
  .use-motion .post-block,
  .use-motion .pagination,
  .use-motion .comments,
  .use-motion .post-header,
  .use-motion .post-body,
  .use-motion .collection-header { opacity: initial; }

  .use-motion .site-title,
  .use-motion .site-subtitle {
    opacity: initial;
    top: initial;
  }

  .use-motion .logo-line-before i { left: initial; }
  .use-motion .logo-line-after i { right: initial; }
  </style>
</noscript>

</head>

<body itemscope itemtype="http://schema.org/WebPage">
  <div class="container use-motion">
    <div class="headband"></div>

    <header class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-container">
  <div class="site-nav-toggle">
    <div class="toggle" aria-label="切换导航栏">
      <span class="toggle-line toggle-line-first"></span>
      <span class="toggle-line toggle-line-middle"></span>
      <span class="toggle-line toggle-line-last"></span>
    </div>
  </div>

  <div class="site-meta">

    <a href="/" class="brand" rel="start">
      <span class="logo-line-before"><i></i></span>
      <h1 class="site-title">邢道荣的个人博客</h1>
      <span class="logo-line-after"><i></i></span>
    </a>
  </div>

  <div class="site-nav-right">
    <div class="toggle popup-trigger">
        <i class="fa fa-search fa-fw fa-lg"></i>
    </div>
  </div>
</div>




<nav class="site-nav">
  <ul id="menu" class="main-menu menu">
        <li class="menu-item menu-item-home">

    <a href="/" rel="section"><i class="fa fa-home fa-fw"></i>首页</a>

  </li>
        <li class="menu-item menu-item-about">

    <a href="/about/" rel="section"><i class="fa fa-user fa-fw"></i>关于</a>

  </li>
        <li class="menu-item menu-item-tags">

    <a href="/tags/" rel="section"><i class="fa fa-tags fa-fw"></i>标签</a>

  </li>
        <li class="menu-item menu-item-categories">

    <a href="/categories/" rel="section"><i class="fa fa-th fa-fw"></i>分类</a>

  </li>
        <li class="menu-item menu-item-archives">

    <a href="/archives/" rel="section"><i class="fa fa-archive fa-fw"></i>归档</a>

  </li>
      <li class="menu-item menu-item-search">
        <a role="button" class="popup-trigger"><i class="fa fa-search fa-fw"></i>搜索
        </a>
      </li>
  </ul>
</nav>



  <div class="search-pop-overlay">
    <div class="popup search-popup">
        <div class="search-header">
  <span class="search-icon">
    <i class="fa fa-search"></i>
  </span>
  <div class="search-input-container">
    <input autocomplete="off" autocapitalize="off"
           placeholder="搜索..." spellcheck="false"
           type="search" class="search-input">
  </div>
  <span class="popup-btn-close">
    <i class="fa fa-times-circle"></i>
  </span>
</div>
<div id="search-result">
  <div id="no-result">
    <i class="fa fa-spinner fa-pulse fa-5x fa-fw"></i>
  </div>
</div>

    </div>
  </div>

</div>
    </header>

    
  <div class="reading-progress-bar"></div>


    <main class="main">
      <div class="main-inner">
        <div class="content-wrap">
          

          <div class="content index posts-expand">
            
      
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://daorongxing.gitee.io/post/57281/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="Daorong Xing">
      <meta itemprop="description" content="这是我的个人博客，记录计算机学习之路！">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="邢道荣的个人博客">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          
            <a href="/post/57281/" class="post-title-link" itemprop="url">3-hashtable</a>
        </h2>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>
              

              <time title="创建时间：2022-12-04 14:56:56 / 修改时间：22:18:51" itemprop="dateCreated datePublished" datetime="2022-12-04T14:56:56+08:00">2022-12-04</time>
            </span>
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-folder"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/%E7%AE%97%E6%B3%95/" itemprop="url" rel="index"><span itemprop="name">算法</span></a>
                </span>
            </span>

          <br>
            <span class="post-meta-item" title="本文字数">
              <span class="post-meta-item-icon">
                <i class="far fa-file-word"></i>
              </span>
                <span class="post-meta-item-text">本文字数：</span>
              <span>3.8k</span>
            </span>
            <span class="post-meta-item" title="阅读时长">
              <span class="post-meta-item-icon">
                <i class="far fa-clock"></i>
              </span>
                <span class="post-meta-item-text">阅读时长 &asymp;</span>
              <span>3 分钟</span>
            </span>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
          <h1 id="1-哈希表基本概念的入门"><a href="#1-哈希表基本概念的入门" class="headerlink" title="1. 哈希表基本概念的入门"></a>1. 哈希表基本概念的入门</h1><p>哈希表也叫散列表，是通过<code>key &amp; value</code>来进行定位的数据结构，他把关键码值映射到表中一个位置来进行定位，这个映射函数叫做哈希函数；<br>元素在数组位置position可以表示为<code>hash(key)</code>， 表面上只存放key，找到key就可以找到value。<br>主要思想是空间换时间，可以节约遍历的时间成本，但是代价是需要建立字典库存储映射结果。</p>
<ul>
<li>数组+链表结构<br>数组查询方便，可以通过下标直接获得所对应的值，但是插入删除不方便，需要整体移动元素还需要扩容；<br>链表查询不方便，没有下标只能通过遍历的方式进行查询，增加插入方便，只需要找到需要插入的节点之后进行插入删除即可；<br>哈希表是两者的结合，获得了两者的优点。<br>哈希碰撞指经过哈希函数两个key都映射到了同一个数组位置上，那么这时候有两种解决方法。</li>
<li>拉链法：在同一个位置进行链表结构的扩充；</li>
<li>线性探索法： 往数组的下一个位置进行扩充；<br>需要考虑到的是<strong>查询效率</strong>，当链表长度过长，那么使用线性探索法；当链表长度足够，使用拉链法。<br>哈希攻击指的是黑客运用一些会转换为相同存储位置的数据注入，最后使得<strong>哈希表退化成一个单链表</strong>，降低了查询效率，DOS(Denial of Service, 拒绝服务供给)攻击.</li>
</ul>
<h2 id="1-1-hashMap"><a href="#1-1-hashMap" class="headerlink" title="1.1 hashMap"></a>1.1 hashMap</h2><h3 id="1-1-1-map基本操作"><a href="#1-1-1-map基本操作" class="headerlink" title="1.1.1 map基本操作"></a>1.1.1 map基本操作</h3><ul>
<li>hashMap的主要Api：<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">map.clear();</span><br><span class="line">map.size();</span><br><span class="line">map.isEmpty</span><br><span class="line">map.containsKey();判断</span><br><span class="line">map.containsValue();</span><br><span class="line">map.get(key);</span><br><span class="line">map.put(key,value);</span><br><span class="line">map.putAll(otherMap);</span><br><span class="line">map.remove(key);</span><br><span class="line">map.getOrDefault(key,defaultValue);查找key的值,不存在则返回默认值。</span><br><span class="line">map.entrySet();用来遍历每一对KV</span><br><span class="line"><span class="title function_">for</span><span class="params">(Map.Entry&lt;Integer，Integer&gt; etntey : map.entrySet()</span>)</span><br></pre></td></tr></table></figure></li>
<li>map遍历三种方式<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 第一种方式： keySet 取出map中所有键，封装为map集合</span></span><br><span class="line">		Set&lt;String&gt; s1=buy.keySet();</span><br><span class="line">		<span class="comment">//开始根据键找值</span></span><br><span class="line">		<span class="keyword">for</span> (String key : s1) &#123;</span><br><span class="line">			Integer value=buy.get(key);</span><br><span class="line">			System.out.println(key+<span class="string">&quot;-&gt;&gt;&gt;&gt;&quot;</span>+value);	</span><br><span class="line">		&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 第二种方式： 将所有键值对取出封装为entrySet集合</span></span><br><span class="line">		Set&lt;Map.Entry&lt;String,Integer&gt;&gt; en=buy.entrySet();</span><br><span class="line">		<span class="keyword">for</span> (Map.Entry&lt;String, Integer&gt; entry : en) &#123;</span><br><span class="line">			String key=entry.getKey();</span><br><span class="line">			Integer value=entry.getValue();</span><br><span class="line">			System.out.println(key+<span class="string">&quot;-&gt;&gt;&gt;&quot;</span>+value);</span><br><span class="line">			</span><br><span class="line">		&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 第三种方式： Lambda表达式遍历</span></span><br><span class="line">		buy.forEach(<span class="keyword">new</span> <span class="title class_">BiConsumer</span>&lt;String, Integer&gt;() &#123;</span><br><span class="line">			<span class="meta">@Override</span></span><br><span class="line">			<span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">accept</span><span class="params">(String t, Integer u)</span> &#123;</span><br><span class="line">				System.out.println(t+<span class="string">&quot;-&gt;&gt;&gt;&quot;</span>+u);</span><br><span class="line">				</span><br><span class="line">			&#125;</span><br><span class="line">		&#125;);</span><br></pre></td></tr></table></figure></li>
</ul>
<h3 id="1-1-2-HashMap两个重要参数"><a href="#1-1-2-HashMap两个重要参数" class="headerlink" title="1.1.2 HashMap两个重要参数"></a>1.1.2 HashMap两个重要参数</h3><ul>
<li>初始容量大小：确定了哈希表底层数组的长度，必须是2的幂，默认初始值为16；</li>
<li>加载因子： 决定什么时候进行扩容，默认为0.75f，当数组存储元素个数超过<code>初始容量大小*加载因子</code>，数组就会用<code>refresh()</code>方法进行扩容，将数组扩大到原来的两倍。<br>扩容十分耗费性能，因为会生成一个新的数组，而且原来元素都要重新计算hashcode存入新的数组。</li>
</ul>
<h3 id="1-1-3-put方法原理"><a href="#1-1-3-put方法原理" class="headerlink" title="1.1.3 put方法原理"></a>1.1.3 put方法原理</h3><p>将key通过本地方法<code>public native int hashcode()</code>， 获取对应key的哈希码， 这个哈希码和key的存储位置有关，一般计算规则是取模存入，假如数组的长度是16个字节，key的hashcode是3214968，那么<code>3214968 mod 16 = 8</code>, 那么key就会被存储在数组的第8个位置，如果该位置为空则直接存入，如果该位置有值，就将插入的key与已经存在的key逐一进行equals判断，如果true就替换values，否则就以链表或红黑树(当链表长度大于8时)形式接入。此时<code>(key, value)</code>被封装为Node节点一同进行put操作</p>
<blockquote>
<p>红黑树是平衡二叉树，在查找的效率方面比链表高。</p>
</blockquote>
<ul>
<li>equals()和hashcode()关系<br>equals()方法对于基本数据类型，比较两个数的内容是否相等，而对于引用数据类型，则比较两个数的存储位置是否相等。<br>两个对象equals()了，那么他们的hashcode()一定相等；两个对象不equals()，他们的hashcode不一定不相等(经过算法可能计算出来相同的值，哈希碰撞的原理)<br>equals()重写了，hashcode()就一定要重写，否则可能两个对象equals，他们的hashcode仍然不相等，可能为后世使用埋下隐患;</li>
</ul>
<h3 id="1-1-4-get-key-方法原理"><a href="#1-1-4-get-key-方法原理" class="headerlink" title="1.1.4 get(key)方法原理"></a>1.1.4 get(key)方法原理</h3><p>首先调用hashcode()方法获取key的hashcode；<br>之后取模定位到数组的索引位置，如果位置为空，返回null；<br>如果有值，逐一遍历将key进行equal判断，成功则放回对应Node中的values；匹配不到返回null。</p>
<h3 id="1-1-5-hashMap-在Java1-7和1-8中的区别"><a href="#1-1-5-hashMap-在Java1-7和1-8中的区别" class="headerlink" title="1.1.5 hashMap 在Java1.7和1.8中的区别"></a>1.1.5 hashMap 在Java1.7和1.8中的区别</h3><h4 id="1-结构不同"><a href="#1-结构不同" class="headerlink" title="1. 结构不同"></a>1. 结构不同</h4><p>1.7采用的是数组+链表的数据结构<br>1.8采用的是数组+链表+红黑树的数据结构(当链表长度大于8时，扩展为红黑树)</p>
<h4 id="2-节点不同"><a href="#2-节点不同" class="headerlink" title="2. 节点不同"></a>2. 节点不同</h4><p>区别：<br>1.8中的hash作为一个常量，可以减少扩容时候再次计算哈希值造成的性能消耗。<br>1.8多了红黑树的节点。</p>
<h4 id="3-hash函数区别"><a href="#3-hash函数区别" class="headerlink" title="3. hash函数区别"></a>3. hash函数区别</h4><p>1.8相较于1.7只采用了一次位运算和一次与运算，而这次的目的是为了能够减少哈希碰撞，将高位和地位融合在一起，因为发现进行取模操作的时候对高位的影响是相对较小的。因为计算公式为<code>(n-1) &amp; hash</code>，对高位基本上是没有什么影响的。</p>
<blockquote>
<p>取模，hash%length，计算机中直接求余效率不如位移运算，源码中做了优化hash&amp;(length-1)，<code>hash % length == hash &amp; (length - 1)</code>的前提是length是2的n次方, 位运算特征，length是2的n次方，那么他减去1之后就是n个1，异或运算同0异1，这时候就能准确得出他在长度内的值是多少了。 </p>
</blockquote>
<h4 id="4-初始化方式"><a href="#4-初始化方式" class="headerlink" title="4. 初始化方式"></a>4. 初始化方式</h4><p>1.7：</p>
<ul>
<li>table是直接赋值给了一个空数组，在第一次put元素时初始化和计算容量。</li>
<li>table是单独定义的inflateTable（）初始化方法创建的。<br>1.8：</li>
<li>table没有赋值，属于懒加载，构造方式时已经计算好了新的容量位置（大于等于给定容量的最小2的次幂）。</li>
<li>table是resize（）方法创建的。</li>
</ul>
<h4 id="5-扩容方式"><a href="#5-扩容方式" class="headerlink" title="5. 扩容方式"></a>5. 扩容方式</h4><p>1.7： 运用异或对哈希值进行重新计算，运用resize()方法负责扩容，inflateTable()负责创建表；<br>1.8： 运用原来的哈希值加上扩容数组长度得到新的数组索引位置，节约了性能利用；表为空时候resize()创建表，表中有数值resize()扩容</p>
<h4 id="6-数据插入方式"><a href="#6-数据插入方式" class="headerlink" title="6. 数据插入方式"></a>6. 数据插入方式</h4><p>1.7： 头插法<br>1.8： 尾插法，避免了在并发时出现逆序和循环链表的情况</p>
<h3 id="1-1-6-线程问题"><a href="#1-1-6-线程问题" class="headerlink" title="1.1.6 线程问题"></a>1.1.6 线程问题</h3><p>1.7 死循环，数据丢失，并发执行扩容阶段<br>1.8 解决死循环，数据丢失仍然没有解决，并发put的时候</p>
<p>整体储存流程如下：<br><img src="/images/20190122151905332.png"></p>
<hr>
<h2 id="1-2-Set"><a href="#1-2-Set" class="headerlink" title="1.2 Set"></a>1.2 Set</h2><h3 id="1-2-1-Set集合基本操作"><a href="#1-2-1-Set集合基本操作" class="headerlink" title="1.2.1 Set集合基本操作"></a>1.2.1 Set集合基本操作</h3><p>list是有序的，元素可以重复的；set是无序的，不能重复的</p>
<ul>
<li>主要Api：<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">boolean</span> <span class="title function_">add</span><span class="params">(E object)</span> <span class="comment">//添加一个元素，添加成功返回true</span></span><br><span class="line"><span class="keyword">void</span> <span class="title function_">clear</span><span class="params">()</span> <span class="comment">//从Set集合中移除所有元素，该方法是从Collection集合继承过来的。</span></span><br><span class="line">Object <span class="title function_">clone</span><span class="params">()</span></span><br><span class="line"><span class="type">boolean</span> <span class="title function_">contains</span><span class="params">(Object object)</span> <span class="comment">//判断集合内是否包含元素</span></span><br><span class="line"><span class="type">boolean</span> <span class="title function_">isEmpty</span><span class="params">()</span> <span class="comment">//判断是否为空集合</span></span><br><span class="line">Iterator&lt;E&gt; <span class="title function_">iterator</span><span class="params">()</span> <span class="comment">//迭代器，遍历set集合用</span></span><br><span class="line"><span class="type">boolean</span> <span class="title function_">remove</span><span class="params">(Object object)</span> <span class="comment">//移除元素</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">size</span><span class="params">()</span> <span class="comment">//数组长度</span></span><br></pre></td></tr></table></figure></li>
<li>遍历方式</li>
</ul>
<ol>
<li>iterator遍历<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">Set&lt;String&gt; set = <span class="keyword">new</span> <span class="title class_">HashSet</span>&lt;String&gt;();  </span><br><span class="line">Iterator&lt;String&gt; it = set.iterator();  </span><br><span class="line"><span class="keyword">while</span> (it.hasNext()) &#123;  </span><br><span class="line">  <span class="type">String</span> <span class="variable">str</span> <span class="operator">=</span> it.next();  </span><br><span class="line">  System.out.println(str);  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li>
<li>增强for遍历<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">for</span> (String str : set) &#123;  </span><br><span class="line">      System.out.println(str);  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li>
</ol>

      
    </div>

    
    
    
      <footer class="post-footer">
        <div class="post-eof"></div>
      </footer>
  </article>
  
  
  

      
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://daorongxing.gitee.io/post/24714/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="Daorong Xing">
      <meta itemprop="description" content="这是我的个人博客，记录计算机学习之路！">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="邢道荣的个人博客">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          
            <a href="/post/24714/" class="post-title-link" itemprop="url">类结构和类加载</a>
        </h2>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>

              <time title="创建时间：2022-12-03 23:00:52" itemprop="dateCreated datePublished" datetime="2022-12-03T23:00:52+08:00">2022-12-03</time>
            </span>
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="far fa-calendar-check"></i>
                </span>
                <span class="post-meta-item-text">更新于</span>
                <time title="修改时间：2022-12-04 22:21:00" itemprop="dateModified" datetime="2022-12-04T22:21:00+08:00">2022-12-04</time>
              </span>
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-folder"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/JVM/" itemprop="url" rel="index"><span itemprop="name">JVM</span></a>
                </span>
            </span>

          <br>
            <span class="post-meta-item" title="本文字数">
              <span class="post-meta-item-icon">
                <i class="far fa-file-word"></i>
              </span>
                <span class="post-meta-item-text">本文字数：</span>
              <span>3k</span>
            </span>
            <span class="post-meta-item" title="阅读时长">
              <span class="post-meta-item-icon">
                <i class="far fa-clock"></i>
              </span>
                <span class="post-meta-item-text">阅读时长 &asymp;</span>
              <span>3 分钟</span>
            </span>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
          <h1 id="1-类文件结构"><a href="#1-类文件结构" class="headerlink" title="1. 类文件结构"></a>1. 类文件结构</h1><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">ClassFile &#123;</span><br><span class="line">    u4             magic; <span class="comment">//Class 文件的标志</span></span><br><span class="line">    u2             minor_version;<span class="comment">//Class 的小版本号</span></span><br><span class="line">    u2             major_version;<span class="comment">//Class 的大版本号</span></span><br><span class="line">    u2             constant_pool_count;<span class="comment">//常量池的数量</span></span><br><span class="line">    cp_info        constant_pool[constant_pool_count-<span class="number">1</span>];<span class="comment">//常量池</span></span><br><span class="line">    u2             access_flags;<span class="comment">//Class 的访问标记</span></span><br><span class="line">    u2             this_class;<span class="comment">//当前类</span></span><br><span class="line">    u2             super_class;<span class="comment">//父类</span></span><br><span class="line">    u2             interfaces_count;<span class="comment">//接口</span></span><br><span class="line">    u2             interfaces[interfaces_count];<span class="comment">//一个类可以实现多个接口</span></span><br><span class="line">    u2             fields_count;<span class="comment">//Class 文件的字段属性</span></span><br><span class="line">    field_info     fields[fields_count];<span class="comment">//一个类会可以有多个字段</span></span><br><span class="line">    u2             methods_count;<span class="comment">//Class 文件的方法数量</span></span><br><span class="line">    method_info    methods[methods_count];<span class="comment">//一个类可以有个多个方法</span></span><br><span class="line">    u2             attributes_count;<span class="comment">//此类的属性表中的属性数</span></span><br><span class="line">    attribute_info attributes[attributes_count];<span class="comment">//属性表集合</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="1-1-魔数-amgic"><a href="#1-1-魔数-amgic" class="headerlink" title="1.1 魔数(amgic)"></a>1.1 魔数(amgic)</h2><p>唯一作用是确定这个文件是否为一个能被虚拟机接受的Class文件。即进行<strong>类型识别</strong>。使用魔数而不使用文件拓展名是为了安全考虑。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">u4             magic; <span class="comment">//Class 文件的标志</span></span><br></pre></td></tr></table></figure>
<h2 id="1-2-版本号-minor-version-amp-major-version"><a href="#1-2-版本号-minor-version-amp-major-version" class="headerlink" title="1.2 版本号(minor_version &amp; major_version)"></a>1.2 版本号(minor_version &amp; major_version)</h2><p>高版本的JDK能向下兼容以前版本的Class文件，但不能运行以后版本的Class文件。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">u2             minor_version;<span class="comment">//Class 的小版本号</span></span><br><span class="line">u2             major_version;<span class="comment">//Class 的大版本号</span></span><br></pre></td></tr></table></figure>
<h2 id="1-3-常量池"><a href="#1-3-常量池" class="headerlink" title="1.3 常量池"></a>1.3 常量池</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">u2             constant_pool_count;<span class="comment">//常量池的数量</span></span><br><span class="line">cp_info        constant_pool[constant_pool_count-<span class="number">1</span>];<span class="comment">//常量池</span></span><br></pre></td></tr></table></figure>
<p><code>constant_pool_count</code>表示常量池的容量，索引从1开始，到他的数量-1.第0项常量表示不引用任何常量，默认为空。</p>
<blockquote>
<p>0x0016：表示为十进制是22，表示有21个常量，索引从1-21<br>主要存放两类常量：字面量和符号引用<br>每一项常量都是一个表，表开始是u1类型的标志位。<br><img src="/images/1bcc0033df92b50d7db8ef484f54e88.png"></p>
</blockquote>
<h2 id="1-4-访问标志"><a href="#1-4-访问标志" class="headerlink" title="1.4 访问标志"></a>1.4 访问标志</h2><p>识别类或接口层次的访问消息。<br><img src="/images/ca3c4e7fd521b481e238d400f9a4757.png"></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">u2             access_flags;<span class="comment">//Class 的访问标记</span></span><br></pre></td></tr></table></figure>
<h2 id="1-5-类索引，父类索引和接口索引集合"><a href="#1-5-类索引，父类索引和接口索引集合" class="headerlink" title="1.5 类索引，父类索引和接口索引集合"></a>1.5 类索引，父类索引和接口索引集合</h2><p>当前类要设置全限名，所有的都有父类，除了java.lang.Object，接口可以多实现。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">u2             this_class;<span class="comment">//当前类</span></span><br><span class="line">u2             super_class;<span class="comment">//父类</span></span><br><span class="line">u2             interfaces_count;<span class="comment">//接口</span></span><br><span class="line">u2             interfaces[interfaces_count];<span class="comment">//一个类可以实现多个接口</span></span><br></pre></td></tr></table></figure>
<h2 id="1-6-字段表集合"><a href="#1-6-字段表集合" class="headerlink" title="1.6 字段表集合"></a>1.6 字段表集合</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">u2             fields_count;<span class="comment">//Class 文件的字段属性</span></span><br><span class="line">field_info     fields[fields_count];<span class="comment">//一个类会可以有多个字段</span></span><br></pre></td></tr></table></figure>
<p>字段表格式：</p>
<ul>
<li><code>access_flags</code>: 字段的作用域（public ,private,protected修饰符），是实例变量还是类变量（static修饰符）,可否被序列化（transient 修饰符）,可变性（final）,可见性（volatile 修饰符，是否强制从主内存读写）。</li>
<li><code>name_index</code>: 对常量池的引用，表示的字段的名称；</li>
<li><code>descriptor_index</code>: 对常量池的引用，表示字段和方法的描述符；</li>
<li><code>attributes_count</code>: 一个字段还会拥有一些额外的属性，attributes_count 存放属性的个数；</li>
<li><code>attributes[attributes_count]</code>: 存放具体属性具体内容。<br>字段表标志位：<br><img src="/images/ba74348c5a074791abadabda1534dbf3.png"></li>
</ul>
<h2 id="1-7-方法表集合"><a href="#1-7-方法表集合" class="headerlink" title="1.7 方法表集合"></a>1.7 方法表集合</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">u2             methods_count;<span class="comment">//Class 文件的方法数量</span></span><br><span class="line">method_info    methods[methods_count];<span class="comment">//一个类可以有个多个方法</span></span><br></pre></td></tr></table></figure>
<p>方法表结构：<br><img src="/images/4efb6101e08445499f2faf59f34963f4.png"><br>方法表标志位：<br><img src="/images/d8137412775c419b948902e79dee14da.png"></p>
<h1 id="2-类加载机制"><a href="#2-类加载机制" class="headerlink" title="2. 类加载机制"></a>2. 类加载机制</h1><p>类的生命周期：<br><img src="/images/b724a4d759f8f67fbdac422a0eac658.png"><br>类加载的时机：</p>
<ul>
<li>创建类的实例，也就是<code>new</code>一个对象。</li>
<li>访问类的静态方法或者静态变量（包含静态变量赋值）。</li>
<li>使用<code>Class.forName()</code>反射类。</li>
<li>子类初始化的时候。</li>
<li>JVM启动时标明的启动类。</li>
</ul>
<h2 id="2-1-加载"><a href="#2-1-加载" class="headerlink" title="2.1 加载"></a>2.1 加载</h2><ol>
<li>通过一个类的全限定名来获取定义此类的二进制字节流。</li>
<li>将这个流的静态存储结构转换为方法区运行时数据结构。</li>
<li>生成一个Class对象<br>jvm是<strong>懒加载</strong>，所以只有使用到类时才会加载，例如调用类的main()方法，new对象等等 ，主类在运行过程中如果使用到其它类，会逐步加载这些类。</li>
</ol>
<h2 id="2-2-验证"><a href="#2-2-验证" class="headerlink" title="2.2 验证"></a>2.2 验证</h2><ul>
<li>文件格式验证</li>
<li>元数据验证</li>
<li>字节码验证</li>
<li>符号引用验证</li>
</ul>
<h2 id="2-3-准备"><a href="#2-3-准备" class="headerlink" title="2.3 准备"></a>2.3 准备</h2><p>为类中定义的变量(被<code>static</code>修饰过的变量)分配内存并设置类变量初始值。此阶段不包含实例变量的赋值。</p>
<h2 id="2-4-解析"><a href="#2-4-解析" class="headerlink" title="2.4 解析"></a>2.4 解析</h2><p>将符号引用转换为直接引用。</p>
<ul>
<li>符号引用： 描述对象，包括如下三种：<br>类和接口的全限定名<br>字段的名称和描述符<br>方法的名称和描述符</li>
<li>直接引用：<br>变量有一个内存地址来标识，如果我们用一个指针指向这个内存地址，这个指针就是直接引用。<br>等我们需要用到这个变量的时候，就可以直接通过指针指向的地址找到。<br>而我们在加载类的时候，解析代码并指向内存某个地址，然后将符号引用 obj和这个内存地址进行映射的过程，就是解析这个步骤要做的事，也叫做符号引用转换为直接引用。</li>
</ul>
<h2 id="2-5-初始化"><a href="#2-5-初始化" class="headerlink" title="2.5 初始化"></a>2.5 初始化</h2><p>（1）对类的静态变量初始化为指定的值<br><code>int initData = 666</code><br>（2）执行静态代码块<br><code>&lt;clinit&gt;()</code></p>
<h1 id="3-类加载器"><a href="#3-类加载器" class="headerlink" title="3. 类加载器"></a>3. 类加载器</h1><h2 id="3-1-类加载器的种类"><a href="#3-1-类加载器的种类" class="headerlink" title="3.1 类加载器的种类"></a>3.1 类加载器的种类</h2><p><img src="/images/47266cb826c74981b21ded13641ed666.png"></p>
<ul>
<li>启动类加载器（Bootstrap ClassLoader）：负责加载Java类的核心类(<code>&lt;JAVA_HOME&gt;\lib</code>目录下，能被<code>-Xbootclasspath</code>参数所指定路径存放的)，是用C++代码实现的，无法被java代码直接引用。</li>
<li>扩展类加载器（Extensions ClassLoader）：负责加载JRE的扩展目录lib&#x2F;ext或者由java.ext.dirs系统属性指定的目录中的JAR包的类。由Java语言实现，父类加载器为Null。</li>
<li>应用程序类加载器（Application ClassLoader）： 负责加载用户类路径 classpath 上所有的 jar 包和 .class 文件。</li>
</ul>
<h2 id="3-2-双亲委派模型"><a href="#3-2-双亲委派模型" class="headerlink" title="3.2 双亲委派模型"></a>3.2 双亲委派模型</h2><p>工作过程：<br>如果一个类加载器收到了类加载的请求，它首先不会自己去尝试加载这个类，而是把这个请求委派给父类加载器去完成，每一个层次的类加载器都是如此，因此所有的夹杂请求最终都应该传送到顶层的启动类加载器中，只有父加载器反馈自己无法完成这个加载请求（它的搜索范围中没有找到所需的类）时，子加载器才会尝试自己去加载。<br>简而言之：<font color=red>自下而上请求，自上而下加载</font><br>优势：<br>父类加载器成功加载则返回，子类加载器不会再加载，防止了重复加载。<br>防止核心API库被随意篡改。比如有一个要加载java.lang.Integer类的请求，通过双亲委派进制加载传递到启动类加载器，在在核心Java API发现这个名字的类，发现该类已被加载，并不会重新加载传递的过来的java.lang.Integer，而直接返回已加载过的Integer.class，可以防止核心API被随意篡改。</p>

      
    </div>

    
    
    
      <footer class="post-footer">
        <div class="post-eof"></div>
      </footer>
  </article>
  
  
  

      
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://daorongxing.gitee.io/post/3701/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="Daorong Xing">
      <meta itemprop="description" content="这是我的个人博客，记录计算机学习之路！">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="邢道荣的个人博客">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          
            <a href="/post/3701/" class="post-title-link" itemprop="url">Spring_1</a>
        </h2>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>
              

              <time title="创建时间：2022-12-03 18:42:12 / 修改时间：18:48:46" itemprop="dateCreated datePublished" datetime="2022-12-03T18:42:12+08:00">2022-12-03</time>
            </span>
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-folder"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/Spring/" itemprop="url" rel="index"><span itemprop="name">Spring</span></a>
                </span>
            </span>

          <br>
            <span class="post-meta-item" title="本文字数">
              <span class="post-meta-item-icon">
                <i class="far fa-file-word"></i>
              </span>
                <span class="post-meta-item-text">本文字数：</span>
              <span>50k</span>
            </span>
            <span class="post-meta-item" title="阅读时长">
              <span class="post-meta-item-icon">
                <i class="far fa-clock"></i>
              </span>
                <span class="post-meta-item-text">阅读时长 &asymp;</span>
              <span>46 分钟</span>
            </span>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
          <h2 id="Spring-day01"><a href="#Spring-day01" class="headerlink" title="Spring_day01"></a>Spring_day01</h2><p><strong>今日目标</strong></p>
<blockquote>
<ul>
<li>掌握Spring相关概念</li>
<li>完成IOC&#x2F;DI的入门案例编写</li>
<li>掌握IOC的相关配置与使用</li>
<li>掌握DI的相关配置与使用</li>
</ul>
</blockquote>
<h2 id="1，课程介绍"><a href="#1，课程介绍" class="headerlink" title="1，课程介绍"></a>1，课程介绍</h2><p>对于一门新技术，我们需要从<code>为什么要学</code>、<code>学什么</code>以及<code>怎么学</code>这三个方向入手来学习。那对于Spring来说:</p>
<h3 id="1-1-为什么要学"><a href="#1-1-为什么要学" class="headerlink" title="1.1 为什么要学?"></a>1.1 为什么要学?</h3><ul>
<li><p>从使用和占有率看</p>
<ul>
<li><p>Spring在市场的占有率与使用率高</p>
</li>
<li><p>Spring在企业的技术选型命中率高</p>
</li>
<li><p>所以说,Spring技术是JavaEE开发必备技能，企业开发技术选型命中率&gt;&#x3D;&#x3D;90%&#x3D;&#x3D;</p>
<p><img src="/images/image-20210729171139088.png"></p>
<p><strong>说明</strong>:对于未使用Spring的项目一般都是些比较老的项目，大多都处于维护阶段。</p>
</li>
</ul>
</li>
<li><p>从专业角度看</p>
<ul>
<li>随着时代发展，软件规模与功能都呈几何式增长，开发难度也在不断递增，该如何解决?<ul>
<li>Spring可以&#x3D;&#x3D;简化开发&#x3D;&#x3D;，降低企业级开发的复杂性，使开发变得更简单快捷</li>
</ul>
</li>
<li>随着项目规模与功能的增长,遇到的问题就会增多，为了解决问题会引入更多的框架，这些框架如何协调工作?<ul>
<li>Spring可以&#x3D;&#x3D;框架整合&#x3D;&#x3D;，高效整合其他技术，提高企业级应用开发与运行效率</li>
</ul>
</li>
</ul>
<p>综上所述，&#x3D;&#x3D;Spring是一款非常优秀而且功能强大的框架，不仅要学，而且还要学好。&#x3D;&#x3D;</p>
</li>
</ul>
<h3 id="1-2-学什么"><a href="#1-2-学什么" class="headerlink" title="1.2 学什么?"></a>1.2 学什么?</h3><p>从上面的介绍中，我们可以看到Spring框架主要的优势是在<code>简化开发</code>和<code>框架整合</code>上，至于如何实现就是咱们要学习Spring框架的主要内容:</p>
<ul>
<li><p>简化开发: Spring框架中提供了两个大的核心技术，分别是:</p>
<ul>
<li>&#x3D;&#x3D;IOC&#x3D;&#x3D;</li>
<li>&#x3D;&#x3D;AOP&#x3D;&#x3D;<ul>
<li>&#x3D;&#x3D;事务处理&#x3D;&#x3D;</li>
</ul>
</li>
</ul>
<p> 1.Spring的简化操作都是基于这两块内容,所以这也是Spring学习中最为重要的两个知识点。</p>
<p> 2.事务处理属于Spring中AOP的具体应用，可以简化项目中的事务管理，也是Spring技术中的一大亮点。</p>
</li>
<li><p>框架整合: Spring在框架整合这块已经做到了极致，它可以整合市面上几乎所有主流框架，比如:</p>
<ul>
<li>&#x3D;&#x3D;MyBatis&#x3D;&#x3D;</li>
<li>MyBatis-plus</li>
<li>Struts</li>
<li>Struts2</li>
<li>Hibernate</li>
<li>……</li>
</ul>
<p>这些框架中，我们目前只学习了MyBatis，所以在Spring框架的学习中，主要是学习如何整合MyBatis。</p>
<p>综上所述，对于Spring的学习，主要学习四块内容:</p>
<p>&#x3D;&#x3D;(1)IOC,(2)整合Mybatis(IOC的具体应用)，(3)AOP,(4)声明式事务(AOP的具体应用)&#x3D;&#x3D;</p>
</li>
</ul>
<h3 id="1-3-怎么学"><a href="#1-3-怎么学" class="headerlink" title="1.3 怎么学?"></a>1.3 怎么学?</h3><ul>
<li>学习Spring框架设计思想<ul>
<li>对于Spring来说，它能迅速占领全球市场，不只是说它的某个功能比较强大，更重要是在它的<code>思想</code>上。</li>
</ul>
</li>
<li>学习基础操作，思考操作与思想间的联系<ul>
<li>掌握了Spring的设计思想，然后就需要通过一些基础操作来思考操作与思想之间的关联关系</li>
</ul>
</li>
<li>学习案例，熟练应用操作的同时，体会思想<ul>
<li>会了基础操作后，就需要通过大量案例来熟练掌握框架的具体应用，加深对设计思想的理解。</li>
</ul>
</li>
</ul>
<p>介绍完<code>为什么要学</code>、<code>学什么</code>和<code>怎么学</code>Spring框架后，大家需要重点掌握的是:</p>
<ul>
<li>Spring很优秀，需要认真重点的学习</li>
<li>Spring的学习主线是IOC、AOP、声明式事务和整合MyBais</li>
</ul>
<p>接下来，咱们就开始进入Spring框架的学习。</p>
<h2 id="2，Spring相关概念"><a href="#2，Spring相关概念" class="headerlink" title="2，Spring相关概念"></a>2，Spring相关概念</h2><h3 id="2-1-初识Spring"><a href="#2-1-初识Spring" class="headerlink" title="2.1 初识Spring"></a>2.1 初识Spring</h3><p>在这一节，主要通过以下两个点来了解下Spring:</p>
<h4 id="2-1-1-Spring家族"><a href="#2-1-1-Spring家族" class="headerlink" title="2.1.1 Spring家族"></a>2.1.1 Spring家族</h4><ul>
<li><p>官网：<a href="https://spring.io，从官网我们可以大概了解到：">https://spring.io，从官网我们可以大概了解到：</a></p>
<ul>
<li>Spring能做什么:用以开发web、微服务以及分布式系统等,光这三块就已经占了JavaEE开发的九成多。</li>
<li>Spring并不是单一的一个技术，而是一个大家族，可以从官网的<code>Projects</code>中查看其包含的所有技术。</li>
</ul>
</li>
<li><p>Spring发展到今天已经形成了一种开发的生态圈,Spring提供了若干个项目,每个项目用于完成特定的功能。</p>
<ul>
<li><p>Spring已形成了完整的生态圈，也就是说我们可以完全使用Spring技术完成整个项目的构建、设计与开发。</p>
</li>
<li><p>Spring有若干个项目，可以根据需要自行选择，把这些个项目组合起来，起了一个名称叫&#x3D;&#x3D;全家桶&#x3D;&#x3D;，如下图所示</p>
<p><img src="/images/image-20210729171850181.png"></p>
<p><strong>说明:</strong></p>
<p>图中的图标都代表什么含义，可以进入<code>https://spring.io/projects</code>网站进行对比查看。</p>
<p>这些技术并不是所有的都需要学习，额外需要重点关注<code>Spring Framework</code>、<code>SpringBoot</code>和<code>SpringCloud</code>:</p>
<p><img src="/images/1629714811435.png"></p>
<ul>
<li>Spring Framework:Spring框架，是Spring中最早最核心的技术，也是所有其他技术的基础。</li>
<li>SpringBoot:Spring是来简化开发，而SpringBoot是来帮助Spring在简化的基础上能更快速进行开发。</li>
<li>SpringCloud:这个是用来做分布式之微服务架构的相关开发。</li>
</ul>
<p>除了上面的这三个技术外，还有很多其他的技术，也比较流行，如SpringData,SpringSecurity等，这些都可以被应用在我们的项目中。我们今天所学习的Spring其实指的是&#x3D;&#x3D;Spring Framework&#x3D;&#x3D;。</p>
</li>
</ul>
</li>
</ul>
<h4 id="2-1-2-了解Spring发展史"><a href="#2-1-2-了解Spring发展史" class="headerlink" title="2.1.2 了解Spring发展史"></a>2.1.2 了解Spring发展史</h4><p> 接下来我们介绍下Spring Framework这个技术是如何来的呢?</p>
<p><img src="/images/image-20210729171926576.png"></p>
<p>Spring发展史</p>
<ul>
<li>IBM(IT公司-国际商业机器公司)在1997年提出了EJB思想,早期的JAVAEE开发大都基于该思想。</li>
<li>Rod Johnson(Java和J2EE开发领域的专家)在2002年出版的<code>Expert One-on-One J2EE Design and Development</code>,书中有阐述在开发中使用EJB该如何做。</li>
<li>Rod Johnson在2004年出版的<code>Expert One-on-One J2EE Development without EJB</code>,书中提出了比EJB思想更高效的实现方案，并且在同年将方案进行了具体的落地实现，这个实现就是Spring1.0。</li>
<li>随着时间推移，版本不断更新维护，目前最新的是Spring5<ul>
<li>Spring1.0是纯配置文件开发</li>
<li>Spring2.0为了简化开发引入了注解开发，此时是配置文件加注解的开发方式</li>
<li>Spring3.0已经可以进行纯注解开发，使开发效率大幅提升，我们的课程会以注解开发为主</li>
<li>Spring4.0根据JDK的版本升级对个别API进行了调整</li>
<li>Spring5.0已经全面支持JDK8，现在Spring最新的是5系列所以建议大家把JDK安装成1.8版</li>
</ul>
</li>
</ul>
<p>本节介绍了Spring家族与Spring的发展史，需要大家重点掌握的是:</p>
<ul>
<li>今天所学的Spring其实是Spring家族中的Spring Framework</li>
<li>Spring Framework是Spring家族中其他框架的底层基础，学好Spring可以为其他Spring框架的学习打好基础</li>
</ul>
<h3 id="2-2-Spring系统架构"><a href="#2-2-Spring系统架构" class="headerlink" title="2.2 Spring系统架构"></a>2.2 Spring系统架构</h3><p>前面我们说spring指的是Spring Framework,那么它其中都包含哪些内容以及我们该如何学习这个框架?</p>
<p>针对这些问题，我们将从<code>系统架构图</code>和<code>课程学习路线</code>来进行说明:</p>
<h4 id="2-2-1-系统架构图"><a href="#2-2-1-系统架构图" class="headerlink" title="2.2.1 系统架构图"></a>2.2.1 系统架构图</h4><ul>
<li><p>Spring Framework是Spring生态圈中最基础的项目，是其他项目的根基。</p>
</li>
<li><p>Spring Framework的发展也经历了很多版本的变更，每个版本都有相应的调整</p>
<p><img src="/images/image-20210729172153796.png"></p>
</li>
<li><p>Spring Framework的5版本目前没有最新的架构图，而最新的是4版本，所以接下来主要研究的是4的架构图</p>
<p><img src="/images/1629720945720.png"></p>
<p>(1)核心层</p>
<ul>
<li>Core Container:核心容器，这个模块是Spring最核心的模块，其他的都需要依赖该模块</li>
</ul>
<p>(2)AOP层</p>
<ul>
<li>AOP:面向切面编程，它依赖核心层容器，目的是&#x3D;&#x3D;在不改变原有代码的前提下对其进行功能增强&#x3D;&#x3D;</li>
<li>Aspects:AOP是思想,Aspects是对AOP思想的具体实现</li>
</ul>
<p>(3)数据层</p>
<ul>
<li>Data Access:数据访问，Spring全家桶中有对数据访问的具体实现技术</li>
<li>Data Integration:数据集成，Spring支持整合其他的数据层解决方案，比如Mybatis</li>
<li>Transactions:事务，Spring中事务管理是Spring AOP的一个具体实现，也是后期学习的重点内容</li>
</ul>
<p>(4)Web层</p>
<ul>
<li>这一层的内容将在SpringMVC框架具体学习</li>
</ul>
<p>(5)Test层</p>
<ul>
<li>Spring主要整合了Junit来完成单元测试和集成测试</li>
</ul>
</li>
</ul>
<h4 id="2-2-2-课程学习路线"><a href="#2-2-2-课程学习路线" class="headerlink" title="2.2.2 课程学习路线"></a>2.2.2 课程学习路线</h4><p>介绍完Spring的体系结构后，从中我们可以得出对于Spring的学习主要包含四部分内容，分别是:</p>
<ul>
<li>&#x3D;&#x3D;Spring的IOC&#x2F;DI&#x3D;&#x3D;</li>
<li>&#x3D;&#x3D;Spring的AOP&#x3D;&#x3D;</li>
<li>&#x3D;&#x3D;AOP的具体应用,事务管理&#x3D;&#x3D;</li>
<li>&#x3D;&#x3D;IOC&#x2F;DI的具体应用,整合Mybatis&#x3D;&#x3D;</li>
</ul>
<p><img src="/images/1629722300996.png"></p>
<p>对于这节的内容，大家重点要记住的是Spring需要学习的四部分内容。接下来就从第一部分开始学起。</p>
<h3 id="2-3-Spring核心概念"><a href="#2-3-Spring核心概念" class="headerlink" title="2.3 Spring核心概念"></a>2.3 Spring核心概念</h3><p>在Spring核心概念这部分内容中主要包含<code>IOC/DI</code>、<code>IOC容器</code>和<code>Bean</code>,那么问题就来了，这些都是什么呢?</p>
<h4 id="2-3-1-目前项目中的问题"><a href="#2-3-1-目前项目中的问题" class="headerlink" title="2.3.1 目前项目中的问题"></a>2.3.1 目前项目中的问题</h4><p>一个概念的提出，总是因为有对应的问题需要去解决，那么我们就需要先分析下目前咱们代码在编写过程中遇到的问题:</p>
<p><img src="/images/1629723232339.png"></p>
<p>(1)业务层需要调用数据层的方法，就需要在业务层new数据层的对象</p>
<p>(2)如果数据层的实现类发生变化，那么业务层的代码也需要跟着改变，发生变更后，都需要进行编译打包和重部署</p>
<p>(3)所以，现在代码在编写的过程中存在的问题是：&#x3D;&#x3D; <strong>耦合度偏高</strong> &#x3D;&#x3D;</p>
<p>针对这个问题，该如何解决呢?</p>
<p><img src="/images/1629724206002.png"></p>
<p>我们就想，如果能把框中的内容给去掉，不就可以降低依赖了么，但是又会引入新的问题，去掉以后程序能运行么?</p>
<p>答案肯定是不行，因为bookDao没有赋值为Null，强行运行就会出空指针异常。</p>
<p>所以现在的问题就是，业务层不想new对象，运行的时候又需要这个对象，该咋办呢?</p>
<p>针对这个问题，Spring就提出了一个解决方案:</p>
<ul>
<li>使用对象时，<mark>在程序中不要主动使用new产生对象，转换为由&#x3D;&#x3D;外部&#x3D;&#x3D;提供对象</mark></li>
</ul>
<p>这种实现思就是Spring的一个核心概念</p>
<h4 id="2-3-2-IOC、IOC容器、Bean、DI"><a href="#2-3-2-IOC、IOC容器、Bean、DI" class="headerlink" title="2.3.2 IOC、IOC容器、Bean、DI"></a>2.3.2 IOC、IOC容器、Bean、DI</h4><ol>
<li>&#x3D;&#x3D;IOC（Inversion of Control）控制反转&#x3D;&#x3D;</li>
</ol>
<p>(1)什么是控制反转呢？</p>
<ul>
<li>使用对象时，由主动new产生对象转换为由&#x3D;&#x3D;外部&#x3D;&#x3D;提供对象，此过程中对象创建控制权由程序转移到外部，此思想称为控制反转。<ul>
<li>业务层要用数据层的类对象，以前是自己<code>new</code>的</li>
<li>现在自己不new了，交给<code>别人[外部]</code>来创建对象</li>
<li><code>别人[外部]</code>就反转控制了数据层对象的创建权</li>
<li>这种思想就是控制反转</li>
<li>别人[外部]指定是什么呢?继续往下学</li>
</ul>
</li>
</ul>
<p>(2)Spring和IOC之间的关系是什么呢?</p>
<ul>
<li>Spring技术对IOC思想进行了<strong>实现</strong></li>
<li>Spring提供了一个容器，称为&#x3D;&#x3D;IOC容器&#x3D;&#x3D;，用来充当IOC思想中的”外部”， IOC容器是IOC思想的具体实现</li>
<li>IOC思想中的<code>别人[外部]</code>指的就是Spring的IOC容器</li>
</ul>
<p>(3)IOC容器的作用以及内部存放的是什么?</p>
<ul>
<li>IOC容器<strong>负责对象的创建</strong>、初始化等一系列工作，其中包含了数据层和业务层的类对象</li>
<li>被创建或被管理的<strong>对象</strong>在IOC容器中统称为**&#x3D;&#x3D;Bean&#x3D;&#x3D;**</li>
<li>IOC容器中放的就是一个个的Bean对象</li>
</ul>
<p>(4)当IOC容器中创建好service和dao对象后，程序能正确执行么?</p>
<ul>
<li>不行，因为service运行需要依赖dao对象</li>
<li>IOC容器中虽然有service和dao对象</li>
<li>但是service对象和dao对象没有任何关系</li>
<li>需要把dao对象交给service,也就是说要<strong>绑定service和dao对象之间的关系</strong></li>
</ul>
<p>像这种在容器中建立对象与对象之间的绑定关系就要用到DI:</p>
<ol start="2">
<li>&#x3D;&#x3D;DI（Dependency Injection）依赖注入&#x3D;&#x3D;</li>
</ol>
<p><img src="/images/1629735078619.png"></p>
<p>(1)什么是依赖注入呢?</p>
<ul>
<li>在容器中建立bean与bean之间的依赖关系的整个过程，称为依赖注入<ul>
<li>业务层要用数据层的类对象，以前是自己<code>new</code>的</li>
<li>现在自己不new了，靠<code>别人[外部其实指的就是IOC容器]</code>来给注入进来</li>
<li>这种思想就是依赖注入</li>
</ul>
</li>
</ul>
<p>(2)IOC容器中哪些bean之间要建立依赖关系呢?</p>
<ul>
<li>这个需要程序员根据业务需求提前建立好关系，如业务层需要依赖数据层，service就要和dao建立依赖关系</li>
</ul>
<p>介绍完Spring的IOC和DI的概念后，我们会发现这两个概念的最终目标就是:&#x3D;&#x3D;充分解耦&#x3D;&#x3D;，具体实现靠:</p>
<ul>
<li>使用IOC容器管理bean（IOC)</li>
<li>在IOC容器内将有依赖关系的bean进行关系绑定（DI）</li>
<li>最终结果为:使用对象时不仅可以直接从IOC容器中获取，并且获取到的bean已经绑定了所有的依赖关系.</li>
</ul>
<h4 id="2-3-3-核心概念小结"><a href="#2-3-3-核心概念小结" class="headerlink" title="2.3.3 核心概念小结"></a>2.3.3 核心概念小结</h4><p>这节比较重要，重点要理解<code>什么是IOC/DI思想</code>、<code>什么是IOC容器</code>和<code>什么是Bean</code>：</p>
<p>(1)什么IOC&#x2F;DI思想?</p>
<ul>
<li>IOC:控制反转，控制反转的是对象的创建权</li>
<li>DI:依赖注入，绑定对象与对象之间的依赖关系</li>
</ul>
<p>(2)什么是IOC容器?</p>
<p>Spring创建了一个容器用来存放所创建的对象，这个容器就叫IOC容器</p>
<p>(3)什么是Bean?</p>
<p>容器中所存放的一个个对象就叫Bean或Bean对象</p>
<h2 id="3，入门案例"><a href="#3，入门案例" class="headerlink" title="3，入门案例"></a>3，入门案例</h2><p>介绍完Spring的核心概念后，接下来我们得思考一个问题就是，Spring到底是如何来实现IOC和DI的，那接下来就通过一些简单的入门案例，来演示下具体实现过程:</p>
<h3 id="3-1-IOC入门案例"><a href="#3-1-IOC入门案例" class="headerlink" title="3.1 IOC入门案例"></a>3.1 IOC入门案例</h3><p>对于入门案例，我们得先<code>分析思路</code>然后再<code>代码实现</code>，</p>
<h4 id="3-1-1-入门案例思路分析"><a href="#3-1-1-入门案例思路分析" class="headerlink" title="3.1.1 入门案例思路分析"></a>3.1.1 入门案例思路分析</h4><p>(1)Spring是使用容器来管理bean对象的，那么管什么? </p>
<ul>
<li>主要管理项目中所使用到的类对象，比如(Service和Dao)</li>
</ul>
<p>(2)如何将被管理的对象告知IOC容器?</p>
<ul>
<li>使用配置文件</li>
</ul>
<p>(3)被管理的对象交给IOC容器，要想从容器中获取对象，就先得思考如何获取到IOC容器?</p>
<ul>
<li>Spring框架提供相应的接口</li>
</ul>
<p>(4)IOC容器得到后，如何从容器中获取bean?</p>
<ul>
<li>调用Spring框架提供对应接口中的方法</li>
</ul>
<p>(5)使用Spring导入哪些坐标?</p>
<ul>
<li>用别人的东西，就需要在pom.xml添加对应的依赖</li>
</ul>
<h4 id="3-1-2-入门案例代码实现"><a href="#3-1-2-入门案例代码实现" class="headerlink" title="3.1.2 入门案例代码实现"></a>3.1.2 入门案例代码实现</h4><blockquote>
<p>需求分析:将BookServiceImpl和BookDaoImpl交给Spring管理，并从容器中获取对应的bean对象进行方法调用。</p>
<p>1.创建Maven的java项目</p>
<p>2.pom.xml添加Spring的依赖jar包</p>
<p>3.创建BookService,BookServiceImpl，BookDao和BookDaoImpl四个类</p>
<p>4.resources下添加spring配置文件，并完成bean的配置</p>
<p>5.使用Spring提供的接口完成IOC容器的创建</p>
<p>6.从容器中获取对象进行方法调用</p>
</blockquote>
<h5 id="步骤1-创建Maven项目"><a href="#步骤1-创建Maven项目" class="headerlink" title="步骤1:创建Maven项目"></a>步骤1:创建Maven项目</h5><p><img src="/images/1629734010072.png"></p>
<h5 id="步骤2-添加Spring的依赖jar包"><a href="#步骤2-添加Spring的依赖jar包" class="headerlink" title="步骤2:添加Spring的依赖jar包"></a>步骤2:添加Spring的依赖jar包</h5><p>pom.xml</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependencies</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-context<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">version</span>&gt;</span>5.2.10.RELEASE<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>junit<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>junit<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">version</span>&gt;</span>4.12<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">scope</span>&gt;</span>test<span class="tag">&lt;/<span class="name">scope</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependencies</span>&gt;</span></span><br></pre></td></tr></table></figure>

<h5 id="步骤3-添加案例中需要的类"><a href="#步骤3-添加案例中需要的类" class="headerlink" title="步骤3:添加案例中需要的类"></a>步骤3:添加案例中需要的类</h5><p>创建BookService,BookServiceImpl，BookDao和BookDaoImpl四个类</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">BookDao</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">save</span><span class="params">()</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">BookDaoImpl</span> <span class="keyword">implements</span> <span class="title class_">BookDao</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">save</span><span class="params">()</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;book dao save ...&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">BookService</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">save</span><span class="params">()</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">BookServiceImpl</span> <span class="keyword">implements</span> <span class="title class_">BookService</span> &#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="type">BookDao</span> <span class="variable">bookDao</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">BookDaoImpl</span>();</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">save</span><span class="params">()</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;book service save ...&quot;</span>);</span><br><span class="line">        bookDao.save();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h5 id="步骤4-添加spring配置文件"><a href="#步骤4-添加spring配置文件" class="headerlink" title="步骤4:添加spring配置文件"></a>步骤4:添加spring配置文件</h5><p>resources下添加spring配置文件applicationContext.xml，并完成bean的配置</p>
<p><img src="/images/1629734336440.png"></p>
<h5 id="步骤5-在配置文件中完成bean的配置"><a href="#步骤5-在配置文件中完成bean的配置" class="headerlink" title="步骤5:在配置文件中完成bean的配置"></a>步骤5:在配置文件中完成bean的配置</h5><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?xml version=<span class="string">&quot;1.0&quot;</span> encoding=<span class="string">&quot;UTF-8&quot;</span>?&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">beans</span> <span class="attr">xmlns</span>=<span class="string">&quot;http://www.springframework.org/schema/beans&quot;</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xmlns:xsi</span>=<span class="string">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xsi:schemaLocation</span>=<span class="string">&quot;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd&quot;</span>&gt;</span></span><br><span class="line"> </span><br><span class="line">    <span class="comment">&lt;!--bean标签标示配置bean</span></span><br><span class="line"><span class="comment">    	id属性标示给bean起名字</span></span><br><span class="line"><span class="comment">    	class属性表示给bean定义类型</span></span><br><span class="line"><span class="comment">	--&gt;</span></span><br><span class="line">	<span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;bookDao&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.itheima.dao.impl.BookDaoImpl&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;bookService&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.itheima.service.impl.BookServiceImpl&quot;</span>/&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;/<span class="name">beans</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p><strong>&#x3D;&#x3D;注意事项：bean定义时id属性在同一个上下文中(配置文件)不能重复&#x3D;&#x3D;</strong></p>
<h5 id="步骤6-获取IOC容器"><a href="#步骤6-获取IOC容器" class="headerlink" title="步骤6:获取IOC容器"></a>步骤6:获取IOC容器</h5><p>使用Spring提供的接口完成IOC容器的创建，创建App类，编写main方法</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">App</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        <span class="comment">//获取IOC容器</span></span><br><span class="line">		<span class="type">ApplicationContext</span> <span class="variable">ctx</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ClassPathXmlApplicationContext</span>(<span class="string">&quot;applicationContext.xml&quot;</span>); </span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h5 id="步骤7-从容器中获取对象进行方法调用"><a href="#步骤7-从容器中获取对象进行方法调用" class="headerlink" title="步骤7:从容器中获取对象进行方法调用"></a>步骤7:从容器中获取对象进行方法调用</h5><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">App</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        <span class="comment">//获取IOC容器</span></span><br><span class="line">		<span class="type">ApplicationContext</span> <span class="variable">ctx</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ClassPathXmlApplicationContext</span>(<span class="string">&quot;applicationContext.xml&quot;</span>); </span><br><span class="line"><span class="comment">//        BookDao bookDao = (BookDao) ctx.getBean(&quot;bookDao&quot;);</span></span><br><span class="line"><span class="comment">//        bookDao.save();</span></span><br><span class="line">        <span class="type">BookService</span> <span class="variable">bookService</span> <span class="operator">=</span> (BookService) ctx.getBean(<span class="string">&quot;bookService&quot;</span>);</span><br><span class="line">        bookService.save();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h5 id="步骤8-运行程序"><a href="#步骤8-运行程序" class="headerlink" title="步骤8:运行程序"></a>步骤8:运行程序</h5><p>测试结果为：</p>
<p><img src="/images/image-20210729184337603.png"></p>
<p>Spring的IOC入门案例已经完成，但是在<code>BookServiceImpl</code>的类中依然存在<code>BookDaoImpl</code>对象的new操作，它们之间的耦合度还是比较高，这块该如何解决，就需要用到下面的<code>DI:依赖注入</code>。</p>
<h3 id="3-2-DI入门案例"><a href="#3-2-DI入门案例" class="headerlink" title="3.2 DI入门案例"></a>3.2 DI入门案例</h3><p>对于DI的入门案例，我们依然先<code>分析思路</code>然后再<code>代码实现</code>，</p>
<h4 id="3-2-1-入门案例思路分析"><a href="#3-2-1-入门案例思路分析" class="headerlink" title="3.2.1 入门案例思路分析"></a>3.2.1 入门案例思路分析</h4><p>(1)要想实现依赖注入，必须要基于IOC管理Bean</p>
<ul>
<li>DI的入门案例要依赖于前面IOC的入门案例</li>
</ul>
<p>(2)Service中使用new形式创建的Dao对象是否保留?</p>
<ul>
<li>需要删除掉，最终要使用IOC容器中的bean对象</li>
</ul>
<p>(3)Service中需要的Dao对象如何进入到Service中?</p>
<ul>
<li>在Service中提供方法，让Spring的IOC容器可以通过该方法传入bean对象</li>
</ul>
<p>(4)Service与Dao间的关系如何描述?</p>
<ul>
<li>使用配置文件</li>
</ul>
<h4 id="3-2-2-入门案例代码实现"><a href="#3-2-2-入门案例代码实现" class="headerlink" title="3.2.2 入门案例代码实现"></a>3.2.2 入门案例代码实现</h4><blockquote>
<p>需求:基于IOC入门案例，在BookServiceImpl类中删除new对象的方式，使用Spring的DI完成Dao层的注入</p>
<p>1.删除业务层中使用new的方式创建的dao对象</p>
<p>2.在业务层提供BookDao的setter方法</p>
<p>3.在配置文件中添加依赖注入的配置</p>
<p>4.运行程序调用方法</p>
</blockquote>
<h5 id="步骤1-去除代码中的new"><a href="#步骤1-去除代码中的new" class="headerlink" title="步骤1: 去除代码中的new"></a>步骤1: 去除代码中的new</h5><p>在BookServiceImpl类中，删除业务层中使用new的方式创建的dao对象</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">BookServiceImpl</span> <span class="keyword">implements</span> <span class="title class_">BookService</span> &#123;</span><br><span class="line">    <span class="comment">//删除业务层中使用new的方式创建的dao对象</span></span><br><span class="line">    <span class="keyword">private</span> BookDao bookDao;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">save</span><span class="params">()</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;book service save ...&quot;</span>);</span><br><span class="line">        bookDao.save();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h5 id="步骤2-为属性提供setter方法"><a href="#步骤2-为属性提供setter方法" class="headerlink" title="步骤2:为属性提供setter方法"></a>步骤2:为属性提供setter方法</h5><p>在BookServiceImpl类中,为BookDao提供setter方法</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">BookServiceImpl</span> <span class="keyword">implements</span> <span class="title class_">BookService</span> &#123;</span><br><span class="line">    <span class="comment">//删除业务层中使用new的方式创建的dao对象</span></span><br><span class="line">    <span class="keyword">private</span> BookDao bookDao;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">save</span><span class="params">()</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;book service save ...&quot;</span>);</span><br><span class="line">        bookDao.save();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//提供对应的set方法</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setBookDao</span><span class="params">(BookDao bookDao)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.bookDao = bookDao;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<h5 id="步骤3-修改配置完成注入"><a href="#步骤3-修改配置完成注入" class="headerlink" title="步骤3:修改配置完成注入"></a>步骤3:修改配置完成注入</h5><p>在配置文件中添加依赖注入的配置</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?xml version=<span class="string">&quot;1.0&quot;</span> encoding=<span class="string">&quot;UTF-8&quot;</span>?&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">beans</span> <span class="attr">xmlns</span>=<span class="string">&quot;http://www.springframework.org/schema/beans&quot;</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xmlns:xsi</span>=<span class="string">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xsi:schemaLocation</span>=<span class="string">&quot;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd&quot;</span>&gt;</span></span><br><span class="line">    <span class="comment">&lt;!--bean标签标示配置bean</span></span><br><span class="line"><span class="comment">    	id属性标示给bean起名字</span></span><br><span class="line"><span class="comment">    	class属性表示给bean定义类型</span></span><br><span class="line"><span class="comment">	--&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;bookDao&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.itheima.dao.impl.BookDaoImpl&quot;</span>/&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;bookService&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.itheima.service.impl.BookServiceImpl&quot;</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!--配置server与dao的关系--&gt;</span></span><br><span class="line">        <span class="comment">&lt;!--property标签表示配置当前bean的属性</span></span><br><span class="line"><span class="comment">        		name属性表示配置哪一个具体的属性</span></span><br><span class="line"><span class="comment">        		ref属性表示参照哪一个bean</span></span><br><span class="line"><span class="comment">		--&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;bookDao&quot;</span> <span class="attr">ref</span>=<span class="string">&quot;bookDao&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;/<span class="name">beans</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>&#x3D;&#x3D;注意:配置中的两个bookDao的含义是不一样的&#x3D;&#x3D;</p>
<ul>
<li>name&#x3D;”bookDao”中<code>bookDao</code>的作用是让Spring的IOC容器在获取到名称后，将首字母大写，前面加set找对应的<code>setBookDao()</code>方法进行对象注入</li>
<li>ref&#x3D;”bookDao”中<code>bookDao</code>的作用是让Spring能在IOC容器中找到id为<code>bookDao</code>的Bean对象给<code>bookService</code>进行注入</li>
<li>综上所述，对应关系如下:</li>
</ul>
<p><img src="/images/1629736314989.png"></p>
<h5 id="步骤4-运行程序"><a href="#步骤4-运行程序" class="headerlink" title="步骤4:运行程序"></a>步骤4:运行程序</h5><p>运行，测试结果为：</p>
<p><img src="/images/image-20210729184337603.png"></p>
<h2 id="4，IOC相关内容"><a href="#4，IOC相关内容" class="headerlink" title="4，IOC相关内容"></a>4，IOC相关内容</h2><p>通过前面两个案例，我们已经学习了<code>bean如何定义配置</code>，<code>DI如何定义配置</code>以及<code>容器对象如何获取</code>的内容，接下来主要是把这三块内容展开进行详细的讲解，深入的学习下这三部分的内容，首先是bean基础配置。</p>
<h3 id="4-1-bean基础配置"><a href="#4-1-bean基础配置" class="headerlink" title="4.1 bean基础配置"></a>4.1 bean基础配置</h3><p>对于bean的配置中，主要会讲解<code>bean基础配置</code>,<code>bean的别名配置</code>,<code>bean的作用范围配置</code>&#x3D;&#x3D;(重点)&#x3D;&#x3D;,这三部分内容：</p>
<h4 id="4-1-1-bean基础配置-id与class"><a href="#4-1-1-bean基础配置-id与class" class="headerlink" title="4.1.1 bean基础配置(id与class)"></a>4.1.1 bean基础配置(id与class)</h4><p>对于bean的基础配置，在前面的案例中已经使用过:</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;bean id=&quot;&quot; class=&quot;&quot;/&gt;</span><br></pre></td></tr></table></figure>

<p>其中，bean标签的功能、使用方式以及id和class属性的作用，我们通过一张图来描述下</p>
<p><img src="/images/image-20210729183500978.png"></p>
<p>这其中需要大家重点掌握的是:&#x3D;&#x3D;bean标签的id和class属性的使用&#x3D;&#x3D;。</p>
<p><strong>思考：</strong></p>
<ul>
<li>class属性能不能写接口如<code>BookDao</code>的类全名呢?</li>
</ul>
<p>答案肯定是不行，因为接口是没办法创建对象的。</p>
<ul>
<li>前面提过为bean设置id时，id必须唯一，但是如果由于命名习惯而产生了分歧后，该如何解决?</li>
</ul>
<p>在解决这个问题之前，我们需要准备下开发环境，对于开发环境我们可以有两种解决方案:</p>
<ul>
<li><p>使用前面IOC和DI的案例</p>
</li>
<li><p>重新搭建一个新的案例环境,目的是方便大家查阅代码</p>
<ul>
<li><p>搭建的内容和前面的案例是一样的，内容如下：</p>
<p><img src="/images/1629769227068.png"></p>
</li>
</ul>
</li>
</ul>
<h4 id="4-1-2-bean的name属性"><a href="#4-1-2-bean的name属性" class="headerlink" title="4.1.2 bean的name属性"></a>4.1.2 bean的name属性</h4><p>环境准备好后，接下来就可以在这个环境的基础上来学习下bean的别名配置，</p>
<p>首先来看下别名的配置说明:</p>
<p><img src="/images/image-20210729183558051.png"></p>
<h5 id="步骤1：配置别名"><a href="#步骤1：配置别名" class="headerlink" title="步骤1：配置别名"></a>步骤1：配置别名</h5><p>打开spring的配置文件applicationContext.xml</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?xml version=<span class="string">&quot;1.0&quot;</span> encoding=<span class="string">&quot;UTF-8&quot;</span>?&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">beans</span> <span class="attr">xmlns</span>=<span class="string">&quot;http://www.springframework.org/schema/beans&quot;</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xmlns:xsi</span>=<span class="string">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xsi:schemaLocation</span>=<span class="string">&quot;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd&quot;</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">&lt;!--name:为bean指定别名，别名可以有多个，使用逗号，分号，空格进行分隔--&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;bookService&quot;</span> <span class="attr">name</span>=<span class="string">&quot;service service4 bookEbi&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.itheima.service.impl.BookServiceImpl&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;bookDao&quot;</span> <span class="attr">ref</span>=<span class="string">&quot;bookDao&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">&lt;!--scope：为bean设置作用范围，可选值为单例singloton，非单例prototype--&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;bookDao&quot;</span> <span class="attr">name</span>=<span class="string">&quot;dao&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.itheima.dao.impl.BookDaoImpl&quot;</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">beans</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p><strong>说明:Ebi全称Enterprise Business Interface，翻译为企业业务接口</strong></p>
<h5 id="步骤2-根据名称容器中获取bean对象"><a href="#步骤2-根据名称容器中获取bean对象" class="headerlink" title="步骤2:根据名称容器中获取bean对象"></a>步骤2:根据名称容器中获取bean对象</h5><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">AppForName</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        <span class="type">ApplicationContext</span> <span class="variable">ctx</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ClassPathXmlApplicationContext</span>(<span class="string">&quot;applicationContext.xml&quot;</span>);</span><br><span class="line">        <span class="comment">//此处根据bean标签的id属性和name属性的任意一个值来获取bean对象</span></span><br><span class="line">        <span class="type">BookService</span> <span class="variable">bookService</span> <span class="operator">=</span> (BookService) ctx.getBean(<span class="string">&quot;service4&quot;</span>);</span><br><span class="line">        bookService.save();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h5 id="步骤3-运行程序"><a href="#步骤3-运行程序" class="headerlink" title="步骤3:运行程序"></a>步骤3:运行程序</h5><p>测试结果为：</p>
<p><img src="/images/image-20210729184337603.png"></p>
<p>&#x3D;&#x3D;注意事项:&#x3D;&#x3D;</p>
<ul>
<li><p>bean依赖注入的ref属性指定bean，必须在容器中存在</p>
<p><img src="/images/1629771744003.png"></p>
</li>
<li><p>如果不存在,则会报错，如下:</p>
<p><img src="/images/1629771880920.png"></p>
<p>这个错误大家需要特别关注下:</p>
<p><img src="/images/1629771972886.png"></p>
<p>获取bean无论是通过id还是name获取，如果无法获取到，将抛出异常&#x3D;&#x3D;NoSuchBeanDefinitionException&#x3D;&#x3D;</p>
</li>
</ul>
<h4 id="4-1-3-bean作用范围scope配置"><a href="#4-1-3-bean作用范围scope配置" class="headerlink" title="4.1.3 bean作用范围scope配置"></a>4.1.3 bean作用范围scope配置</h4><p>关于bean的作用范围是bean属性配置的一个&#x3D;&#x3D;重点&#x3D;&#x3D;内容。</p>
<p>看到这个作用范围，我们就得思考bean的作用范围是来控制bean哪块内容的?</p>
<p>我们先来看下<code>bean作用范围的配置属性</code>:</p>
<p><img src="/images/image-20210729183628138.png"></p>
<h5 id="4-1-3-1-验证IOC容器中对象是否为单例"><a href="#4-1-3-1-验证IOC容器中对象是否为单例" class="headerlink" title="4.1.3.1 验证IOC容器中对象是否为单例"></a>4.1.3.1 验证IOC容器中对象是否为单例</h5><h6 id="验证思路"><a href="#验证思路" class="headerlink" title="验证思路"></a>验证思路</h6><p>​	同一个bean获取两次，将对象打印到控制台，看打印出的地址值是否一致。</p>
<h6 id="具体实现"><a href="#具体实现" class="headerlink" title="具体实现"></a>具体实现</h6><ul>
<li><p>创建一个AppForScope的类，在其main方法中来验证</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">AppForScope</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        <span class="type">ApplicationContext</span> <span class="variable">ctx</span> <span class="operator">=</span> <span class="keyword">new</span> </span><br><span class="line">            <span class="title class_">ClassPathXmlApplicationContext</span>(<span class="string">&quot;applicationContext.xml&quot;</span>);</span><br><span class="line"></span><br><span class="line">        <span class="type">BookDao</span> <span class="variable">bookDao1</span> <span class="operator">=</span> (BookDao) ctx.getBean(<span class="string">&quot;bookDao&quot;</span>);</span><br><span class="line">        <span class="type">BookDao</span> <span class="variable">bookDao2</span> <span class="operator">=</span> (BookDao) ctx.getBean(<span class="string">&quot;bookDao&quot;</span>);</span><br><span class="line">        System.out.println(bookDao1);</span><br><span class="line">        System.out.println(bookDao2);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
<li><p>打印，观察控制台的打印结果</p>
<p><img src="/images/1629772538893.png"></p>
</li>
<li><p>结论:默认情况下，Spring创建的bean对象都是单例的</p>
</li>
</ul>
<p>获取到结论后，问题就来了，那如果我想创建出来非单例的bean对象，该如何实现呢?</p>
<h5 id="4-1-3-2-配置bean为非单例"><a href="#4-1-3-2-配置bean为非单例" class="headerlink" title="4.1.3.2 配置bean为非单例"></a>4.1.3.2 配置bean为非单例</h5><p>在Spring配置文件中，配置scope属性来实现bean的非单例创建</p>
<ul>
<li><p>在Spring的配置文件中，修改<code>&lt;bean&gt;</code>的scope属性</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;bookDao&quot;</span> <span class="attr">name</span>=<span class="string">&quot;dao&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.itheima.dao.impl.BookDaoImpl&quot;</span> <span class="attr">scope</span>=<span class="string">&quot;&quot;</span>/&gt;</span></span><br></pre></td></tr></table></figure>
</li>
<li><p>将scope设置为<code>singleton</code></p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;bookDao&quot;</span> <span class="attr">name</span>=<span class="string">&quot;dao&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.itheima.dao.impl.BookDaoImpl&quot;</span> <span class="attr">scope</span>=<span class="string">&quot;singleton&quot;</span>/&gt;</span></span><br></pre></td></tr></table></figure>

<p>运行AppForScope，打印看结果</p>
<p><img src="/images/1629772538893.png"></p>
</li>
<li><p>将scope设置为<code>prototype</code></p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;bean id=&quot;bookDao&quot; name=&quot;dao&quot; class=&quot;com.itheima.dao.impl.BookDaoImpl&quot; scope=&quot;prototype&quot;/&gt;</span><br></pre></td></tr></table></figure>

<p>运行AppForScope，打印看结果</p>
<p><img src="/images/1629772928714.png"></p>
</li>
<li><p>结论，使用bean的<code>scope</code>属性可以控制bean的创建是否为单例：</p>
<ul>
<li><code>singleton</code>默认为单例</li>
<li><code>prototype</code>为非单例</li>
</ul>
</li>
</ul>
<h5 id="4-1-3-3-scope使用后续思考"><a href="#4-1-3-3-scope使用后续思考" class="headerlink" title="4.1.3.3 scope使用后续思考"></a>4.1.3.3 scope使用后续思考</h5><p>介绍完<code>scope</code>属性以后，我们来思考几个问题:</p>
<ul>
<li><p>为什么bean默认为单例?</p>
<ul>
<li>bean为单例的意思是在Spring的IOC容器中<strong>只会有该类的一个对象</strong></li>
<li>bean对象只有一个就<strong>避免了对象的频繁创建与销毁</strong>，达到了bean对象的<strong>复用，性能高</strong></li>
</ul>
</li>
<li><p>bean在容器中是单例的，会不会产生<strong>线程安全</strong>问题?</p>
<ul>
<li><p>如果对象是<mark>有状态</mark>对象，即该对象有成员变量可以用来存储数据的，</p>
<p>因为所有请求线程共用一个bean对象，所以会存在线程安全问题。</p>
</li>
<li><p>如果对象是<mark>无状态</mark>对象，即该对象没有成员变量没有进行数据存储的，</p>
<p>因方法中的<strong>局部变量在方法调用完成后会被销毁</strong>，所以不会存在线程安全问题。</p>
</li>
</ul>
</li>
<li><p>哪些bean对象适合交给容器进行管理?</p>
<ul>
<li>表现层对象</li>
<li>业务层对象</li>
<li>数据层对象</li>
<li>工具对象</li>
</ul>
</li>
<li><p>哪些bean对象不适合交给容器进行管理?</p>
<ul>
<li>封装<strong>实例</strong>的域对象，因为会引发线程安全问题，所以不适合。</li>
</ul>
</li>
</ul>
<h4 id="4-14-bean基础配置小结"><a href="#4-14-bean基础配置小结" class="headerlink" title="4.14 bean基础配置小结"></a>4.14 bean基础配置小结</h4><p>关于bean的基础配置中，需要大家掌握以下属性:</p>
<p><img src="/images/1631529887695.png"></p>
<h3 id="4-2-bean实例化"><a href="#4-2-bean实例化" class="headerlink" title="4.2 bean实例化"></a>4.2 bean实例化</h3><p>对象已经能交给Spring的IOC容器来创建了，但是容器是如何来创建对象的呢?</p>
<p>就需要研究下<code>bean的实例化过程</code>，在这块内容中主要解决两部分内容，分别是</p>
<ul>
<li>bean是如何创建的</li>
<li>实例化bean的三种方式，<code>构造方法(重点)</code>,<code>静态工厂</code>，<code>实例工厂()</code>，<code>FactoryBean()(重点)</code></li>
</ul>
<p>在讲解这三种创建方式之前，我们需要先确认一件事:</p>
<p>bean本质上就是对象，对象在new的时候会使用构造方法完成，那创建bean也是使用构造方法完成的。</p>
<p>基于这个知识点出发，我们来验证spring中bean的三种创建方式，</p>
<h4 id="4-2-1-环境准备"><a href="#4-2-1-环境准备" class="headerlink" title="4.2.1 环境准备"></a>4.2.1 环境准备</h4><p>为了方便大家阅读代码，重新准备个开发环境，</p>
<ul>
<li>创建一个Maven项目</li>
<li>pom.xml添加依赖</li>
<li>resources下添加spring的配置文件applicationContext.xml</li>
</ul>
<p>这些步骤和前面的都一致，大家可以快速的拷贝即可，最终项目的结构如下:</p>
<p><img src="/images/1629775585694.png"></p>
<h4 id="4-2-2-构造方法实例化"><a href="#4-2-2-构造方法实例化" class="headerlink" title="4.2.2 构造方法实例化"></a>4.2.2 构造方法实例化</h4><p>在上述的环境下，我们来研究下Spring中的第一种bean的创建方式<code>构造方法实例化</code>:</p>
<h5 id="步骤1-准备需要被创建的类"><a href="#步骤1-准备需要被创建的类" class="headerlink" title="步骤1:准备需要被创建的类"></a>步骤1:准备需要被创建的类</h5><p>准备一个BookDao和BookDaoImpl类</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">BookDao</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">save</span><span class="params">()</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">BookDaoImpl</span> <span class="keyword">implements</span> <span class="title class_">BookDao</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">save</span><span class="params">()</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;book dao save ...&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h5 id="步骤2-将类配置到Spring容器"><a href="#步骤2-将类配置到Spring容器" class="headerlink" title="步骤2:将类配置到Spring容器"></a>步骤2:将类配置到Spring容器</h5><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?xml version=<span class="string">&quot;1.0&quot;</span> encoding=<span class="string">&quot;UTF-8&quot;</span>?&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">beans</span> <span class="attr">xmlns</span>=<span class="string">&quot;http://www.springframework.org/schema/beans&quot;</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xmlns:xsi</span>=<span class="string">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xsi:schemaLocation</span>=<span class="string">&quot;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd&quot;</span>&gt;</span></span><br><span class="line"></span><br><span class="line">	<span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;bookDao&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.itheima.dao.impl.BookDaoImpl&quot;</span>/&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;/<span class="name">beans</span>&gt;</span></span><br></pre></td></tr></table></figure>

<h5 id="步骤3-编写运行程序"><a href="#步骤3-编写运行程序" class="headerlink" title="步骤3:编写运行程序"></a>步骤3:编写运行程序</h5><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">AppForInstanceBook</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        <span class="type">ApplicationContext</span> <span class="variable">ctx</span> <span class="operator">=</span> <span class="keyword">new</span> </span><br><span class="line">            <span class="title class_">ClassPathXmlApplicationContext</span>(<span class="string">&quot;applicationContext.xml&quot;</span>);</span><br><span class="line">        <span class="type">BookDao</span> <span class="variable">bookDao</span> <span class="operator">=</span> (BookDao) ctx.getBean(<span class="string">&quot;bookDao&quot;</span>);</span><br><span class="line">        bookDao.save();</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h5 id="步骤4-类中提供构造函数测试"><a href="#步骤4-类中提供构造函数测试" class="headerlink" title="步骤4:类中提供构造函数测试"></a>步骤4:类中提供构造函数测试</h5><p>在BookDaoImpl类中添加一个无参构造函数，并打印一句话，方便观察结果。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">BookDaoImpl</span> <span class="keyword">implements</span> <span class="title class_">BookDao</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">BookDaoImpl</span><span class="params">()</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;book dao constructor is running ....&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">save</span><span class="params">()</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;book dao save ...&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>运行程序，如果控制台有打印构造函数中的输出，说明Spring容器在创建对象的时候也走的是构造函数</p>
<p><img src="/images/1629775972507.png"></p>
<h5 id="步骤5-将构造函数改成private测试"><a href="#步骤5-将构造函数改成private测试" class="headerlink" title="步骤5:将构造函数改成private测试"></a>步骤5:将构造函数改成private测试</h5><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">BookDaoImpl</span> <span class="keyword">implements</span> <span class="title class_">BookDao</span> &#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="title function_">BookDaoImpl</span><span class="params">()</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;book dao constructor is running ....&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">save</span><span class="params">()</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;book dao save ...&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>运行程序，能执行成功,说明内部走的依然是构造函数,能访问到类中的私有构造方法,因为无论私有公有都能够被访问，所以我们可以说，<strong>Spring底层用的是反射</strong></p>
<p><img src="/images/1629775972507.png"></p>
<h5 id="步骤6-构造函数中添加一个参数测试"><a href="#步骤6-构造函数中添加一个参数测试" class="headerlink" title="步骤6:构造函数中添加一个参数测试"></a>步骤6:构造函数中添加一个参数测试</h5><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">BookDaoImpl</span> <span class="keyword">implements</span> <span class="title class_">BookDao</span> &#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="title function_">BookDaoImpl</span><span class="params">(<span class="type">int</span> i)</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;book dao constructor is running ....&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">save</span><span class="params">()</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;book dao save ...&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>运行程序，</p>
<p>程序会报错，说明Spring底层使用的是<strong>类的无参构造方法</strong>。</p>
<p>（原因：有参构造器通常意味着类要进行实例化，而实例化的类在IOC的单例模式下很容易造成线程安全问题，所以IOC拒绝访问有参构造器生成的对象）</p>
<p><img src="/images/1629776331499.png"></p>
<p><mark>底层是运用反射获取类的无参构造器来构造类的单例对象。</mark></p>
<h4 id="4-2-3-分析Spring的错误信息-简单看看就好了"><a href="#4-2-3-分析Spring的错误信息-简单看看就好了" class="headerlink" title="4.2.3 分析Spring的错误信息(简单看看就好了)"></a>4.2.3 分析Spring的错误信息(简单看看就好了)</h4><p>接下来，我们主要研究下Spring的报错信息来学一学如阅读。</p>
<ul>
<li><p>错误信息从下往上依次查看，因为上面的错误大都是对下面错误的一个包装，最核心错误是在最下面</p>
<blockquote>
<p>Caused by: java.lang.NoSuchMethodException: com.itheima.dao.impl.BookDaoImpl.<code>&lt;init&gt;</code>()</p>
</blockquote>
<ul>
<li>Caused by 翻译为<code>引起</code>，即出现错误的原因</li>
<li>java.lang.NoSuchMethodException:抛出的异常为<code>没有这样的方法异常</code></li>
<li>com.itheima.dao.impl.BookDaoImpl.<code>&lt;init&gt;</code>():哪个类的哪个方法没有被找到导致的异常，<code>&lt;init&gt;</code>()指定是类的构造方法，即该类的无参构造方法</li>
</ul>
</li>
</ul>
<p>如果最后一行错误获取不到错误信息，接下来查看第二层:</p>
<blockquote>
<p> Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.itheima.dao.impl.BookDaoImpl]: No default constructor found; nested exception is java.lang.NoSuchMethodException: com.itheima.dao.impl.BookDaoImpl.<code>&lt;init&gt;</code>()</p>
</blockquote>
<ul>
<li>nested:嵌套的意思，后面的异常内容和最底层的异常是一致的<ul>
<li>Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.itheima.dao.impl.BookDaoImpl]: No default constructor found; <ul>
<li>Caused by: <code>引发</code></li>
<li>BeanInstantiationException:翻译为<code>bean实例化异常</code></li>
<li>No default constructor found:没有一个默认的构造函数被发现</li>
</ul>
</li>
</ul>
</li>
</ul>
<p>看到这其实错误已经比较明显，给大家个练习，把倒数第三层的错误分析下吧:</p>
<blockquote>
<p> Exception in thread “main” org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘bookDao’ defined in class path resource [applicationContext.xml]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.itheima.dao.impl.BookDaoImpl]: No default constructor found; nested exception is java.lang.NoSuchMethodException: com.itheima.dao.impl.BookDaoImpl.<code>&lt;init&gt;</code>()。</p>
</blockquote>
<p>至此，关于Spring的构造方法实例化就已经学习完了，因为每一个类默认都会提供一个无参构造函数，所以其实真正在使用这种方式的时候，我们什么也不需要做。这也是我们以后比较常用的一种方式。</p>
<h4 id="4-2-4-静态工厂实例化"><a href="#4-2-4-静态工厂实例化" class="headerlink" title="4.2.4 静态工厂实例化"></a>4.2.4 静态工厂实例化</h4><p>接下来研究Spring中的第二种bean的创建方式<code>静态工厂实例化</code>:</p>
<h5 id="4-2-4-1-工厂方式创建bean"><a href="#4-2-4-1-工厂方式创建bean" class="headerlink" title="4.2.4.1 工厂方式创建bean"></a>4.2.4.1 工厂方式创建bean</h5><p>在讲这种方式之前，我们需要先回顾一个知识点是使用工厂来创建对象的方式:</p>
<p>(1)准备一个OrderDao和OrderDaoImpl类</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">OrderDao</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">save</span><span class="params">()</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">OrderDaoImpl</span> <span class="keyword">implements</span> <span class="title class_">OrderDao</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">save</span><span class="params">()</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;order dao save ...&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>(2)创建一个工厂类OrderDaoFactory并提供一个&#x3D;&#x3D;静态方法&#x3D;&#x3D;</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//静态工厂创建对象</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">OrderDaoFactory</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> OrderDao <span class="title function_">getOrderDao</span><span class="params">()</span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">OrderDaoImpl</span>();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>(3)编写AppForInstanceOrder运行类，在类中通过工厂获取对象</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">AppForInstanceOrder</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        <span class="comment">//通过静态工厂创建对象</span></span><br><span class="line">        <span class="type">OrderDao</span> <span class="variable">orderDao</span> <span class="operator">=</span> OrderDaoFactory.getOrderDao();</span><br><span class="line">        orderDao.save();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>(4)运行后，可以查看到结果</p>
<p><img src="/images/1629786862329.png"></p>
<p>如果代码中对象是通过上面的这种方式来创建的，如何将其交给Spring来管理呢?</p>
<h5 id="4-2-4-2-静态工厂实例化"><a href="#4-2-4-2-静态工厂实例化" class="headerlink" title="4.2.4.2 静态工厂实例化"></a>4.2.4.2 静态工厂实例化</h5><p>这就要用到Spring中的静态工厂实例化的知识了，具体实现步骤为:</p>
<p>(1)在spring的配置文件application.properties中添加以下内容:</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;orderDao&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.itheima.factory.OrderDaoFactory&quot;</span> <span class="attr">factory-method</span>=<span class="string">&quot;getOrderDao&quot;</span>/&gt;</span></span><br></pre></td></tr></table></figure>

<p>class:工厂类的类全名</p>
<p>factory-mehod:具体工厂类中创建对象的方法名</p>
<p>对应关系如下图:</p>
<p><img src="/images/image-20210729195248948.png"></p>
<p>(2)在AppForInstanceOrder运行类，使用从IOC容器中获取bean的方法进行运行测试</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">AppForInstanceOrder</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        <span class="type">ApplicationContext</span> <span class="variable">ctx</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ClassPathXmlApplicationContext</span>(<span class="string">&quot;applicationContext.xml&quot;</span>);</span><br><span class="line"></span><br><span class="line">        <span class="type">OrderDao</span> <span class="variable">orderDao</span> <span class="operator">=</span> (OrderDao) ctx.getBean(<span class="string">&quot;orderDao&quot;</span>);</span><br><span class="line"></span><br><span class="line">        orderDao.save();</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>(3)运行后，可以查看到结果</p>
<p><img src="/images/1629786862329.png"></p>
<p>看到这，可能有人会问了，你这种方式在工厂类中不也是直接new对象的，和我自己直接new没什么太大的区别，而且静态工厂的方式反而更复杂，这种方式的意义是什么?</p>
<p>主要的原因是:</p>
<ul>
<li>在工厂的静态方法中，我们除了new对象还可以做其他的一些业务操作，这些操作必不可少,如:</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">OrderDaoFactory</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> OrderDao <span class="title function_">getOrderDao</span><span class="params">()</span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;factory setup....&quot;</span>);<span class="comment">//模拟必要的业务操作</span></span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">OrderDaoImpl</span>();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>之前new对象的方式就无法添加其他的业务内容，重新运行，查看结果:</p>
<p><img src="/images/1629788036885.png"></p>
<p>介绍完静态工厂实例化后，这种方式一般是用来兼容早期的一些老系统，所以&#x3D;&#x3D;了解为主&#x3D;&#x3D;。</p>
<h4 id="4-2-5-实例工厂与FactoryBean"><a href="#4-2-5-实例工厂与FactoryBean" class="headerlink" title="4.2.5 实例工厂与FactoryBean"></a>4.2.5 实例工厂与FactoryBean</h4><p>接下来继续来研究Spring的第三种bean的创建方式<code>实例工厂实例化</code>:</p>
<h5 id="4-2-3-1-环境准备"><a href="#4-2-3-1-环境准备" class="headerlink" title="4.2.3.1 环境准备"></a>4.2.3.1 环境准备</h5><p>(1)准备一个UserDao和UserDaoImpl类</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">UserDao</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">save</span><span class="params">()</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">UserDaoImpl</span> <span class="keyword">implements</span> <span class="title class_">UserDao</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">save</span><span class="params">()</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;user dao save ...&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>(2)创建一个工厂类OrderDaoFactory并提供一个普通方法，注意此处和静态工厂的工厂类不一样的地方是方法不是静态方法</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">UserDaoFactory</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> UserDao <span class="title function_">getUserDao</span><span class="params">()</span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">UserDaoImpl</span>();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>(3)编写AppForInstanceUser运行类，在类中通过工厂获取对象</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">AppForInstanceUser</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        <span class="comment">//创建实例工厂对象</span></span><br><span class="line">        <span class="type">UserDaoFactory</span> <span class="variable">userDaoFactory</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">UserDaoFactory</span>();</span><br><span class="line">        <span class="comment">//通过实例工厂对象创建对象</span></span><br><span class="line">        <span class="type">UserDao</span> <span class="variable">userDao</span> <span class="operator">=</span> userDaoFactory.getUserDao();</span><br><span class="line">        userDao.save();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>(4)运行后，可以查看到结果</p>
<p><img src="/images/1629788769436.png"></p>
<p>对于上面这种实例工厂的方式如何交给Spring管理呢?</p>
<h5 id="4-2-3-2-实例工厂实例化"><a href="#4-2-3-2-实例工厂实例化" class="headerlink" title="4.2.3.2 实例工厂实例化"></a>4.2.3.2 实例工厂实例化</h5><p>具体实现步骤为:</p>
<p>(1)在spring的配置文件中添加以下内容:</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;userFactory&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.itheima.factory.UserDaoFactory&quot;</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;userDao&quot;</span> <span class="attr">factory-method</span>=<span class="string">&quot;getUserDao&quot;</span> <span class="attr">factory-bean</span>=<span class="string">&quot;userFactory&quot;</span>/&gt;</span></span><br></pre></td></tr></table></figure>

<p>实例化工厂运行的顺序是:</p>
<ul>
<li><p>创建实例化工厂对象,对应的是第一行配置</p>
</li>
<li><p>调用对象中的方法来创建bean，对应的是第二行配置</p>
<ul>
<li><p>factory-bean:工厂的实例对象</p>
</li>
<li><p>factory-method:工厂对象中的具体创建对象的方法名,对应关系如下:</p>
<p><img src="/images/image-20210729200203249.png"></p>
</li>
</ul>
</li>
</ul>
<p>factory-mehod:具体工厂类中创建对象的方法名</p>
<p>(2)在AppForInstanceUser运行类，使用从IOC容器中获取bean的方法进行运行测试</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">AppForInstanceUser</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        <span class="type">ApplicationContext</span> <span class="variable">ctx</span> <span class="operator">=</span> <span class="keyword">new</span> </span><br><span class="line">            <span class="title class_">ClassPathXmlApplicationContext</span>(<span class="string">&quot;applicationContext.xml&quot;</span>);</span><br><span class="line">        <span class="type">UserDao</span> <span class="variable">userDao</span> <span class="operator">=</span> (UserDao) ctx.getBean(<span class="string">&quot;userDao&quot;</span>);</span><br><span class="line">        userDao.save();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>(3)运行后，可以查看到结果</p>
<p><img src="/images/1629788769436.png"></p>
<p>实例工厂实例化的方式就已经介绍完了，配置的过程还是比较复杂，所以Spring为了简化这种配置方式就提供了一种叫<code>FactoryBean</code>的方式来简化开发。</p>
<h5 id="4-2-3-3-FactoryBean的使用"><a href="#4-2-3-3-FactoryBean的使用" class="headerlink" title="4.2.3.3 FactoryBean的使用"></a>4.2.3.3 FactoryBean的使用</h5><p>具体的使用步骤为:</p>
<p>(1)创建一个UserDaoFactoryBean的类，实现FactoryBean接口，重写接口的方法</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">UserDaoFactoryBean</span> <span class="keyword">implements</span> <span class="title class_">FactoryBean</span>&lt;UserDao&gt; &#123;</span><br><span class="line">    <span class="comment">//代替原始实例工厂中创建对象的方法</span></span><br><span class="line">    <span class="keyword">public</span> UserDao <span class="title function_">getObject</span><span class="params">()</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">UserDaoImpl</span>();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//返回所创建类的Class对象</span></span><br><span class="line">    <span class="keyword">public</span> Class&lt;?&gt; getObjectType() &#123;</span><br><span class="line">        <span class="keyword">return</span> UserDao.class;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>(2)在Spring的配置文件中进行配置</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;userDao&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.itheima.factory.UserDaoFactoryBean&quot;</span>/&gt;</span></span><br></pre></td></tr></table></figure>

<p>(3)AppForInstanceUser运行类不用做任何修改，直接运行</p>
<p><img src="/images/1629788769436.png"></p>
<p>这种方式在Spring去整合其他框架的时候会被用到，所以这种方式需要大家理解掌握。</p>
<p>查看源码会发现，FactoryBean接口其实会有三个方法，分别是:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">T <span class="title function_">getObject</span><span class="params">()</span> <span class="keyword">throws</span> Exception;</span><br><span class="line"></span><br><span class="line">Class&lt;?&gt; getObjectType();</span><br><span class="line"></span><br><span class="line"><span class="keyword">default</span> <span class="type">boolean</span> <span class="title function_">isSingleton</span><span class="params">()</span> &#123;</span><br><span class="line">		<span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>方法一:getObject()，被重写后，在方法中进行对象的创建并返回</p>
<p>方法二:getObjectType(),被重写后，主要返回的是被创建类的Class对象</p>
<p>方法三:没有被重写，因为它已经给了默认值，从方法名中可以看出其作用是设置对象是否为单例，默认true，从意思上来看，我们猜想默认应该是单例，如何来验证呢?</p>
<p>思路很简单，就是从容器中获取该对象的多个值，打印到控制台，查看是否为同一个对象。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">AppForInstanceUser</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        <span class="type">ApplicationContext</span> <span class="variable">ctx</span> <span class="operator">=</span> <span class="keyword">new</span> </span><br><span class="line">            <span class="title class_">ClassPathXmlApplicationContext</span>(<span class="string">&quot;applicationContext.xml&quot;</span>);</span><br><span class="line">        <span class="type">UserDao</span> <span class="variable">userDao1</span> <span class="operator">=</span> (UserDao) ctx.getBean(<span class="string">&quot;userDao&quot;</span>);</span><br><span class="line">        <span class="type">UserDao</span> <span class="variable">userDao2</span> <span class="operator">=</span> (UserDao) ctx.getBean(<span class="string">&quot;userDao&quot;</span>);</span><br><span class="line">        System.out.println(userDao1);</span><br><span class="line">        System.out.println(userDao2);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>打印结果，如下:</p>
<p><img src="/images/1629790070607.png"></p>
<p>通过验证，会发现默认是单例，那如果想改成单例具体如何实现?</p>
<p>只需要将isSingleton()方法进行重写，修改返回为false，即可</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//FactoryBean创建对象</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">UserDaoFactoryBean</span> <span class="keyword">implements</span> <span class="title class_">FactoryBean</span>&lt;UserDao&gt; &#123;</span><br><span class="line">    <span class="comment">//代替原始实例工厂中创建对象的方法</span></span><br><span class="line">    <span class="keyword">public</span> UserDao <span class="title function_">getObject</span><span class="params">()</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">UserDaoImpl</span>();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> Class&lt;?&gt; getObjectType() &#123;</span><br><span class="line">        <span class="keyword">return</span> UserDao.class;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">isSingleton</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>重新运行AppForInstanceUser，查看结果</p>
<p><img src="/images/1629790197860.png"></p>
<p>从结果中可以看出现在已经是非单例了，但是一般情况下我们都会采用单例，也就是采用默认即可。所以isSingleton()方法一般不需要进行重写。</p>
<h4 id="4-2-6-bean实例化小结"><a href="#4-2-6-bean实例化小结" class="headerlink" title="4.2.6 bean实例化小结"></a>4.2.6 bean实例化小结</h4><p>通过这一节的学习，需要掌握:</p>
<p>(1)bean是如何创建的呢?</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">构造方法</span><br></pre></td></tr></table></figure>

<p>(2)Spring的IOC实例化对象的三种方式分别是:</p>
<ul>
<li>构造方法(常用)</li>
<li>静态工厂(了解)</li>
<li>实例工厂(了解)<ul>
<li>FactoryBean(实用)</li>
</ul>
</li>
</ul>
<p>这些方式中，重点掌握<code>构造方法</code>和<code>FactoryBean</code>即可。</p>
<p>需要注意的一点是，构造方法在类中默认会提供，但是如果重写了构造方法，默认的就会消失，在使用的过程中需要注意，如果需要重写构造方法，最好把默认的构造方法也重写下。</p>
<h3 id="4-3-bean的生命周期"><a href="#4-3-bean的生命周期" class="headerlink" title="4.3 bean的生命周期"></a>4.3 bean的生命周期</h3><p>关于bean的相关知识还有最后一个是<code>bean的生命周期</code>,对于生命周期，我们主要围绕着<code>bean生命周期控制</code>来讲解:</p>
<ul>
<li>首先理解下什么是生命周期?<ul>
<li>从创建到消亡的完整过程,例如人<strong>从出生到死亡</strong>的整个过程就是一个生命周期。</li>
</ul>
</li>
<li>bean生命周期是什么?<ul>
<li>bean对象从创建到销毁的整体过程。</li>
</ul>
</li>
<li>bean生命周期控制是什么?<ul>
<li>在bean创建后到销毁前做一些事情。</li>
</ul>
</li>
</ul>
<p>现在我们面临的问题是如何在bean的创建之后和销毁之前把我们需要添加的内容添加进去。</p>
<h4 id="4-3-1-环境准备"><a href="#4-3-1-环境准备" class="headerlink" title="4.3.1 环境准备"></a>4.3.1 环境准备</h4><p>还是老规矩，为了方便大家后期代码的阅读，我们重新搭建下环境:</p>
<ul>
<li>创建一个Maven项目</li>
<li>pom.xml添加依赖</li>
<li>resources下添加spring的配置文件applicationContext.xml</li>
</ul>
<p>这些步骤和前面的都一致，大家可以快速的拷贝即可，最终项目的结构如下:</p>
<p><img src="/images/1629791473409.png"></p>
<p>(1)项目中添加BookDao、BookDaoImpl、BookService和BookServiceImpl类</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">BookDao</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">save</span><span class="params">()</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">BookDaoImpl</span> <span class="keyword">implements</span> <span class="title class_">BookDao</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">save</span><span class="params">()</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;book dao save ...&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">BookService</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">save</span><span class="params">()</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">BookServiceImpl</span> <span class="keyword">implements</span> <span class="title class_">BookService</span>&#123;</span><br><span class="line">    <span class="keyword">private</span> BookDao bookDao;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setBookDao</span><span class="params">(BookDao bookDao)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.bookDao = bookDao;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">save</span><span class="params">()</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;book service save ...&quot;</span>);</span><br><span class="line">        bookDao.save();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>(2)resources下提供spring的配置文件</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?xml version=<span class="string">&quot;1.0&quot;</span> encoding=<span class="string">&quot;UTF-8&quot;</span>?&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">beans</span> <span class="attr">xmlns</span>=<span class="string">&quot;http://www.springframework.org/schema/beans&quot;</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xmlns:xsi</span>=<span class="string">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xsi:schemaLocation</span>=<span class="string">&quot;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd&quot;</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;bookDao&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.itheima.dao.impl.BookDaoImpl&quot;</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">beans</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>(3)编写AppForLifeCycle运行类，加载Spring的IOC容器，并从中获取对应的bean对象</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">AppForLifeCycle</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">( String[] args )</span> &#123;</span><br><span class="line">        <span class="type">ApplicationContext</span> <span class="variable">ctx</span> <span class="operator">=</span> <span class="keyword">new</span> </span><br><span class="line">        	<span class="title class_">ClassPathXmlApplicationContext</span>(<span class="string">&quot;applicationContext.xml&quot;</span>);</span><br><span class="line">        <span class="type">BookDao</span> <span class="variable">bookDao</span> <span class="operator">=</span> (BookDao) ctx.getBean(<span class="string">&quot;bookDao&quot;</span>);</span><br><span class="line">        bookDao.save();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h4 id="4-3-2-生命周期设置"><a href="#4-3-2-生命周期设置" class="headerlink" title="4.3.2 生命周期设置"></a>4.3.2 生命周期设置</h4><p>接下来，在上面这个环境中来为BookDao添加生命周期的控制方法，具体的控制有两个阶段:</p>
<ul>
<li>bean<strong>创建之后</strong>，想要添加内容，比如用<strong>来初始化需要用到资源</strong></li>
<li>bean销毁之前，想要添加内容，比如用来释放用到的资源</li>
</ul>
<h5 id="步骤1-添加初始化和销毁方法"><a href="#步骤1-添加初始化和销毁方法" class="headerlink" title="步骤1:添加初始化和销毁方法"></a>步骤1:添加初始化和销毁方法</h5><p>针对这两个阶段，我们在BooDaoImpl类中分别添加两个方法，&#x3D;&#x3D;方法名任意&#x3D;&#x3D;</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">BookDaoImpl</span> <span class="keyword">implements</span> <span class="title class_">BookDao</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">save</span><span class="params">()</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;book dao save ...&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//表示bean初始化对应的操作</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">init</span><span class="params">()</span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;init...&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//表示bean销毁前对应的操作</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">destory</span><span class="params">()</span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;destory...&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h5 id="步骤2-配置生命周期"><a href="#步骤2-配置生命周期" class="headerlink" title="步骤2:配置生命周期"></a>步骤2:配置生命周期</h5><p>在配置文件添加配置，如下:</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;bookDao&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.itheima.dao.impl.BookDaoImpl&quot;</span> <span class="attr">init-method</span>=<span class="string">&quot;init&quot;</span> <span class="attr">destroy-method</span>=<span class="string">&quot;destory&quot;</span>/&gt;</span></span><br></pre></td></tr></table></figure>

<h5 id="步骤3-运行程序-1"><a href="#步骤3-运行程序-1" class="headerlink" title="步骤3:运行程序"></a>步骤3:运行程序</h5><p>运行AppForLifeCycle打印结果为:</p>
<p><img src="/images/1629792339889.png"></p>
<p>从结果中可以看出，init方法执行了，但是destroy方法却未执行，这是为什么呢?</p>
<ul>
<li>Spring的IOC容器是运行在JVM中</li>
<li>运行main方法后,JVM启动,Spring加载配置文件生成IOC容器,从容器获取bean对象，然后调方法执行</li>
<li>main方法执行完后，JVM退出，这个时候IOC容器中的bean还没有来得及销毁就已经结束了</li>
<li>所以没有调用对应的destroy方法</li>
</ul>
<p>知道了出现问题的原因，具体该如何解决呢?</p>
<h4 id="4-3-3-close关闭容器"><a href="#4-3-3-close关闭容器" class="headerlink" title="4.3.3 close关闭容器"></a>4.3.3 close关闭容器</h4><ul>
<li><p>ApplicationContext中没有close方法</p>
</li>
<li><p>需要将ApplicationContext更换成ClassPathXmlApplicationContext</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">ClassPathXmlApplicationContext</span> <span class="variable">ctx</span> <span class="operator">=</span> <span class="keyword">new</span> </span><br><span class="line">    <span class="title class_">ClassPathXmlApplicationContext</span>(<span class="string">&quot;applicationContext.xml&quot;</span>);</span><br></pre></td></tr></table></figure>
</li>
<li><p>调用ctx的close()方法</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ctx.close();</span><br></pre></td></tr></table></figure>
</li>
<li><p>运行程序，就能执行destroy方法的内容</p>
<p><img src="/images/1629792857608.png"></p>
</li>
</ul>
<h4 id="4-3-4-注册钩子关闭容器"><a href="#4-3-4-注册钩子关闭容器" class="headerlink" title="4.3.4 注册钩子关闭容器"></a>4.3.4 注册钩子关闭容器</h4><ul>
<li><p>在容器未关闭之前，提前设置好回调函数，让JVM在退出之前回调此函数来关闭容器</p>
</li>
<li><p>调用ctx的<code>registerShutdownHook()</code>方法</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ctx.registerShutdownHook();</span><br></pre></td></tr></table></figure>

<p>**注意:**registerShutdownHook在ApplicationContext中也没有</p>
</li>
<li><p>运行后，查询打印结果</p>
<p><img src="/images/1629792857608.png"></p>
</li>
</ul>
<p>两种方式介绍完后，close和registerShutdownHook选哪个?</p>
<p>相同点:这两种都能用来关闭容器</p>
<p>不同点:close()是在调用的时候关闭，registerShutdownHook()是在JVM退出前调用关闭。</p>
<p>分析上面的实现过程，会发现添加初始化和销毁方法，即需要编码也需要配置，实现起来步骤比较多也比较乱。</p>
<p>Spring提供了两个接口来完成生命周期的控制，好处是可以不用再进行配置<code>init-method</code>和<code>destroy-method</code></p>
<p>接下来在BookServiceImpl完成这两个接口的使用:</p>
<p>修改BookServiceImpl类，添加两个接口<code>InitializingBean</code>， <code>DisposableBean</code>并实现接口中的两个方法<code>afterPropertiesSet</code>和<code>destroy</code></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">BookServiceImpl</span> <span class="keyword">implements</span> <span class="title class_">BookService</span>, InitializingBean, DisposableBean &#123;</span><br><span class="line">    <span class="keyword">private</span> BookDao bookDao;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setBookDao</span><span class="params">(BookDao bookDao)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.bookDao = bookDao;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">save</span><span class="params">()</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;book service save ...&quot;</span>);</span><br><span class="line">        bookDao.save(); </span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">destroy</span><span class="params">()</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;service destroy&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">afterPropertiesSet</span><span class="params">()</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;service init&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>重新运行AppForLifeCycle类，</p>
<p><img src="/images/1629794527419.png"></p>
<p>那第二种方式的实现，我们也介绍完了。</p>
<p><strong>小细节</strong></p>
<ul>
<li><p>对于InitializingBean接口中的afterPropertiesSet方法，翻译过来为<code>属性设置之后</code>。</p>
</li>
<li><p>对于BookServiceImpl来说，bookDao是它的一个属性</p>
</li>
<li><p>setBookDao方法是Spring的IOC容器为其注入属性的方法</p>
</li>
<li><p>思考:afterPropertiesSet和setBookDao谁先执行?</p>
<ul>
<li><p>从方法名分析，猜想应该是setBookDao方法先执行</p>
</li>
<li><p>验证思路，在setBookDao方法中添加一句话</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setBookDao</span><span class="params">(BookDao bookDao)</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;set .....&quot;</span>);</span><br><span class="line">        <span class="built_in">this</span>.bookDao = bookDao;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>
</li>
<li><p>重新运行AppForLifeCycle，打印结果如下:</p>
<p><img src="/images/1629794928636.png"></p>
<p>验证的结果和我们猜想的结果是一致的，所以初始化方法会在类中属性设置之后执行。</p>
</li>
</ul>
</li>
</ul>
<h4 id="4-3-5-bean生命周期小结"><a href="#4-3-5-bean生命周期小结" class="headerlink" title="4.3.5 bean生命周期小结"></a>4.3.5 bean生命周期小结</h4><p>(1)关于Spring中对bean生命周期控制提供了两种方式:</p>
<ul>
<li>在配置文件中的bean标签中添加<code>init-method</code>和<code>destroy-method</code>属性</li>
<li>类实现<code>InitializingBean</code>与<code>DisposableBean</code>接口，这种方式了解下即可。</li>
</ul>
<p>(2)对于bean的生命周期控制在bean的整个生命周期中所处的位置如下:</p>
<ul>
<li>初始化容器<ul>
<li>1.创建对象(内存分配)</li>
<li>2.执行构造方法</li>
<li>3.执行属性注入(set操作)</li>
<li>&#x3D;&#x3D;4.执行bean初始化方法&#x3D;&#x3D;</li>
</ul>
</li>
<li>使用bean<ul>
<li>1.执行业务操作</li>
</ul>
</li>
<li>关闭&#x2F;销毁容器<ul>
<li>&#x3D;&#x3D;1.执行bean销毁方法&#x3D;&#x3D;</li>
</ul>
</li>
</ul>
<p>(3)关闭容器的两种方式:</p>
<ul>
<li>ConfigurableApplicationContext是ApplicationContext的子类<ul>
<li>close()方法</li>
<li>registerShutdownHook()方法</li>
</ul>
</li>
</ul>
<h2 id="5，DI相关内容"><a href="#5，DI相关内容" class="headerlink" title="5，DI相关内容"></a>5，DI相关内容</h2><p>前面我们已经完成了bean相关操作的讲解，接下来就进入第二个大的模块<code>DI依赖注入</code>，首先来介绍下Spring中有哪些注入方式?</p>
<p>我们先来思考</p>
<ul>
<li>向一个类中传递数据的方式有几种?<ul>
<li>普通方法(set方法)</li>
<li>构造方法</li>
</ul>
</li>
<li>依赖注入描述了在容器中建立bean与bean之间的依赖关系的过程，如果bean运行需要的是数字或字符串呢?<ul>
<li>引用类型</li>
<li>简单类型(基本数据类型与String)</li>
</ul>
</li>
</ul>
<p>Spring就是基于上面这些知识点，为我们提供了两种注入方式，分别是:</p>
<ul>
<li>setter注入<ul>
<li>简单类型</li>
<li>&#x3D;&#x3D;引用类型&#x3D;&#x3D;</li>
</ul>
</li>
<li>构造器注入<ul>
<li>简单类型</li>
<li>引用类型</li>
</ul>
</li>
</ul>
<p>依赖注入的方式已经介绍完，接下来挨个学习下:</p>
<h3 id="5-1-setter注入"><a href="#5-1-setter注入" class="headerlink" title="5.1 setter注入"></a>5.1 setter注入</h3><ol>
<li>对于setter方式注入引用类型的方式之前已经学习过，快速回顾下:</li>
</ol>
<ul>
<li>在bean中定义引用类型属性，并提供可访问的&#x3D;&#x3D;set&#x3D;&#x3D;方法</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">BookServiceImpl</span> <span class="keyword">implements</span> <span class="title class_">BookService</span> &#123;</span><br><span class="line">    <span class="keyword">private</span> BookDao bookDao;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setBookDao</span><span class="params">(BookDao bookDao)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.bookDao = bookDao;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<ul>
<li>配置中使用&#x3D;&#x3D;property&#x3D;&#x3D;标签&#x3D;&#x3D;ref&#x3D;&#x3D;属性注入引用类型对象</li>
</ul>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;bookService&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.itheima.service.impl.BookServiceImpl&quot;</span>&gt;</span></span><br><span class="line">	<span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;bookDao&quot;</span> <span class="attr">ref</span>=<span class="string">&quot;bookDao&quot;</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;bookDao&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.itheima.dao.imipl.BookDaoImpl&quot;</span>/&gt;</span></span><br></pre></td></tr></table></figure>

<h4 id="5-1-1-环境准备"><a href="#5-1-1-环境准备" class="headerlink" title="5.1.1 环境准备"></a>5.1.1 环境准备</h4><p>为了更好的学习下面内容，我们依旧准备一个新环境:</p>
<ul>
<li>创建一个Maven项目</li>
<li>pom.xml添加依赖</li>
<li>resources下添加spring的配置文件</li>
</ul>
<p>这些步骤和前面的都一致，大家可以快速的拷贝即可，最终项目的结构如下:</p>
<p><img src="/images/1629799214191.png"></p>
<p>(1)项目中添加BookDao、BookDaoImpl、UserDao、UserDaoImpl、BookService和BookServiceImpl类</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">BookDao</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">save</span><span class="params">()</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">BookDaoImpl</span> <span class="keyword">implements</span> <span class="title class_">BookDao</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">save</span><span class="params">()</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;book dao save ...&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">UserDao</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">save</span><span class="params">()</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">UserDaoImpl</span> <span class="keyword">implements</span> <span class="title class_">UserDao</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">save</span><span class="params">()</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;user dao save ...&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">BookService</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">save</span><span class="params">()</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">BookServiceImpl</span> <span class="keyword">implements</span> <span class="title class_">BookService</span>&#123;</span><br><span class="line">    <span class="keyword">private</span> BookDao bookDao;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setBookDao</span><span class="params">(BookDao bookDao)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.bookDao = bookDao;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">save</span><span class="params">()</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;book service save ...&quot;</span>);</span><br><span class="line">        bookDao.save();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>(2)resources下提供spring的配置文件</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?xml version=<span class="string">&quot;1.0&quot;</span> encoding=<span class="string">&quot;UTF-8&quot;</span>?&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">beans</span> <span class="attr">xmlns</span>=<span class="string">&quot;http://www.springframework.org/schema/beans&quot;</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xmlns:xsi</span>=<span class="string">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xsi:schemaLocation</span>=<span class="string">&quot;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd&quot;</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;bookDao&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.itheima.dao.impl.BookDaoImpl&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;bookService&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.itheima.service.impl.BookServiceImpl&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;bookDao&quot;</span> <span class="attr">ref</span>=<span class="string">&quot;bookDao&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">beans</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>(3)编写AppForDISet运行类，加载Spring的IOC容器，并从中获取对应的bean对象</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">AppForDISet</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">( String[] args )</span> &#123;</span><br><span class="line">        <span class="type">ApplicationContext</span> <span class="variable">ctx</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ClassPathXmlApplicationContext</span>(<span class="string">&quot;applicationContext.xml&quot;</span>);</span><br><span class="line">        <span class="type">BookService</span> <span class="variable">bookService</span> <span class="operator">=</span> (BookService) ctx.getBean(<span class="string">&quot;bookService&quot;</span>);</span><br><span class="line">        bookService.save();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>接下来，在上面这个环境中来完成setter注入的学习:</p>
<h4 id="5-1-2-注入引用数据类型"><a href="#5-1-2-注入引用数据类型" class="headerlink" title="5.1.2 注入引用数据类型"></a>5.1.2 注入引用数据类型</h4><blockquote>
<p>需求:在bookServiceImpl对象中注入userDao</p>
<p>1.在BookServiceImpl中声明userDao属性</p>
<p>2.为userDao属性提供setter方法</p>
<p>3.在配置文件中使用property标签注入</p>
</blockquote>
<h5 id="步骤1-声明属性并提供setter方法"><a href="#步骤1-声明属性并提供setter方法" class="headerlink" title="步骤1:声明属性并提供setter方法"></a>步骤1:声明属性并提供setter方法</h5><p>在BookServiceImpl中声明userDao属性，并提供setter方法</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">BookServiceImpl</span> <span class="keyword">implements</span> <span class="title class_">BookService</span>&#123;</span><br><span class="line">    <span class="keyword">private</span> BookDao bookDao;</span><br><span class="line">    <span class="keyword">private</span> UserDao userDao;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setUserDao</span><span class="params">(UserDao userDao)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.userDao = userDao;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setBookDao</span><span class="params">(BookDao bookDao)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.bookDao = bookDao;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">save</span><span class="params">()</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;book service save ...&quot;</span>);</span><br><span class="line">        bookDao.save();</span><br><span class="line">        userDao.save();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h5 id="步骤2-配置文件中进行注入配置"><a href="#步骤2-配置文件中进行注入配置" class="headerlink" title="步骤2:配置文件中进行注入配置"></a>步骤2:配置文件中进行注入配置</h5><p>在applicationContext.xml配置文件中使用property标签注入</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?xml version=<span class="string">&quot;1.0&quot;</span> encoding=<span class="string">&quot;UTF-8&quot;</span>?&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">beans</span> <span class="attr">xmlns</span>=<span class="string">&quot;http://www.springframework.org/schema/beans&quot;</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xmlns:xsi</span>=<span class="string">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xsi:schemaLocation</span>=<span class="string">&quot;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd&quot;</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;bookDao&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.itheima.dao.impl.BookDaoImpl&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;userDao&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.itheima.dao.impl.UserDaoImpl&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;bookService&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.itheima.service.impl.BookServiceImpl&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;bookDao&quot;</span> <span class="attr">ref</span>=<span class="string">&quot;bookDao&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;userDao&quot;</span> <span class="attr">ref</span>=<span class="string">&quot;userDao&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">beans</span>&gt;</span></span><br></pre></td></tr></table></figure>

<h5 id="步骤3-运行程序-2"><a href="#步骤3-运行程序-2" class="headerlink" title="步骤3:运行程序"></a>步骤3:运行程序</h5><p>运行AppForDISet类，查看结果，说明userDao已经成功注入。</p>
<p><img src="/images/1629799873386.png"></p>
<h4 id="5-1-3-注入简单数据类型"><a href="#5-1-3-注入简单数据类型" class="headerlink" title="5.1.3 注入简单数据类型"></a>5.1.3 注入简单数据类型</h4><blockquote>
<p>需求：给BookDaoImpl注入一些简单数据类型的数据</p>
<p>参考引用数据类型的注入，我们可以推出具体的步骤为:</p>
<p>1.在BookDaoImpl类中声明对应的简单数据类型的属性</p>
<p>2.为这些属性提供对应的setter方法</p>
<p>3.在applicationContext.xml中配置</p>
</blockquote>
<p><strong>思考:</strong></p>
<p>引用类型使用的是<code>&lt;property name=&quot;&quot; ref=&quot;&quot;/&gt;</code>,简单数据类型还是使用ref么?</p>
<p>ref是指向Spring的IOC容器中的另一个bean对象的，对于简单数据类型，没有对应的bean对象，该如何配置?</p>
<h5 id="步骤1-声明属性并提供setter方法-1"><a href="#步骤1-声明属性并提供setter方法-1" class="headerlink" title="步骤1:声明属性并提供setter方法"></a>步骤1:声明属性并提供setter方法</h5><p>在BookDaoImpl类中声明对应的简单数据类型的属性,并提供对应的setter方法</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">BookDaoImpl</span> <span class="keyword">implements</span> <span class="title class_">BookDao</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> String databaseName;</span><br><span class="line">    <span class="keyword">private</span> <span class="type">int</span> connectionNum;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setConnectionNum</span><span class="params">(<span class="type">int</span> connectionNum)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.connectionNum = connectionNum;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setDatabaseName</span><span class="params">(String databaseName)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.databaseName = databaseName;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">save</span><span class="params">()</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;book dao save ...&quot;</span>+databaseName+<span class="string">&quot;,&quot;</span>+connectionNum);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h5 id="步骤2-配置文件中进行注入配置-1"><a href="#步骤2-配置文件中进行注入配置-1" class="headerlink" title="步骤2:配置文件中进行注入配置"></a>步骤2:配置文件中进行注入配置</h5><p>在applicationContext.xml配置文件中使用property标签注入</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?xml version=<span class="string">&quot;1.0&quot;</span> encoding=<span class="string">&quot;UTF-8&quot;</span>?&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">beans</span> <span class="attr">xmlns</span>=<span class="string">&quot;http://www.springframework.org/schema/beans&quot;</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xmlns:xsi</span>=<span class="string">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xsi:schemaLocation</span>=<span class="string">&quot;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd&quot;</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;bookDao&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.itheima.dao.impl.BookDaoImpl&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;databaseName&quot;</span> <span class="attr">value</span>=<span class="string">&quot;mysql&quot;</span>/&gt;</span></span><br><span class="line">     	<span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;connectionNum&quot;</span> <span class="attr">value</span>=<span class="string">&quot;10&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;userDao&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.itheima.dao.impl.UserDaoImpl&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;bookService&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.itheima.service.impl.BookServiceImpl&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;bookDao&quot;</span> <span class="attr">ref</span>=<span class="string">&quot;bookDao&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;userDao&quot;</span> <span class="attr">ref</span>=<span class="string">&quot;userDao&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">beans</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p><strong>说明:</strong></p>
<p>value:后面跟的是简单数据类型，对于参数类型，Spring在注入的时候会自动转换，但是不能写成</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;connectionNum&quot;</span> <span class="attr">value</span>=<span class="string">&quot;abc&quot;</span>/&gt;</span></span><br></pre></td></tr></table></figure>

<p>这样的话，spring在将<code>abc</code>转换成int类型的时候就会报错。</p>
<h5 id="步骤3-运行程序-3"><a href="#步骤3-运行程序-3" class="headerlink" title="步骤3:运行程序"></a>步骤3:运行程序</h5><p>运行AppForDISet类，查看结果，说明userDao已经成功注入。</p>
<p><img src="/images/1629800324721.png"></p>
<p>**注意:**两个property注入标签的顺序可以任意。</p>
<p>对于setter注入方式的基本使用就已经介绍完了，</p>
<ul>
<li>对于引用数据类型使用的是<code>&lt;property name=&quot;&quot; ref=&quot;&quot;/&gt;</code></li>
<li>对于简单数据类型使用的是<code>&lt;property name=&quot;&quot; value=&quot;&quot;/&gt;</code></li>
</ul>
<h3 id="5-2-构造器注入"><a href="#5-2-构造器注入" class="headerlink" title="5.2 构造器注入"></a>5.2 构造器注入</h3><h4 id="5-2-1-环境准备"><a href="#5-2-1-环境准备" class="headerlink" title="5.2.1 环境准备"></a>5.2.1 环境准备</h4><p>构造器注入也就是构造方法注入，学习之前，还是先准备下环境:</p>
<ul>
<li>创建一个Maven项目</li>
<li>pom.xml添加依赖</li>
<li>resources下添加spring的配置文件</li>
</ul>
<p>这些步骤和前面的都一致，大家可以快速的拷贝即可，最终项目的结构如下:</p>
<p><img src="/images/1629800748639.png"></p>
<p>(1)项目中添加BookDao、BookDaoImpl、UserDao、UserDaoImpl、BookService和BookServiceImpl类</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">BookDao</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">save</span><span class="params">()</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">BookDaoImpl</span> <span class="keyword">implements</span> <span class="title class_">BookDao</span> &#123;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">private</span> String databaseName;</span><br><span class="line">    <span class="keyword">private</span> <span class="type">int</span> connectionNum;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">save</span><span class="params">()</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;book dao save ...&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">UserDao</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">save</span><span class="params">()</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">UserDaoImpl</span> <span class="keyword">implements</span> <span class="title class_">UserDao</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">save</span><span class="params">()</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;user dao save ...&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">BookService</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">save</span><span class="params">()</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">BookServiceImpl</span> <span class="keyword">implements</span> <span class="title class_">BookService</span>&#123;</span><br><span class="line">    <span class="keyword">private</span> BookDao bookDao;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setBookDao</span><span class="params">(BookDao bookDao)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.bookDao = bookDao;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">save</span><span class="params">()</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;book service save ...&quot;</span>);</span><br><span class="line">        bookDao.save();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>(2)resources下提供spring的配置文件</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?xml version=<span class="string">&quot;1.0&quot;</span> encoding=<span class="string">&quot;UTF-8&quot;</span>?&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">beans</span> <span class="attr">xmlns</span>=<span class="string">&quot;http://www.springframework.org/schema/beans&quot;</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xmlns:xsi</span>=<span class="string">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xsi:schemaLocation</span>=<span class="string">&quot;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd&quot;</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;bookDao&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.itheima.dao.impl.BookDaoImpl&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;bookService&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.itheima.service.impl.BookServiceImpl&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;bookDao&quot;</span> <span class="attr">ref</span>=<span class="string">&quot;bookDao&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">beans</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>(3)编写AppForDIConstructor运行类，加载Spring的IOC容器，并从中获取对应的bean对象</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">AppForDIConstructor</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">( String[] args )</span> &#123;</span><br><span class="line">        <span class="type">ApplicationContext</span> <span class="variable">ctx</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ClassPathXmlApplicationContext</span>(<span class="string">&quot;applicationContext.xml&quot;</span>);</span><br><span class="line">        <span class="type">BookService</span> <span class="variable">bookService</span> <span class="operator">=</span> (BookService) ctx.getBean(<span class="string">&quot;bookService&quot;</span>);</span><br><span class="line">        bookService.save();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h4 id="5-2-2-构造器注入引用数据类型"><a href="#5-2-2-构造器注入引用数据类型" class="headerlink" title="5.2.2 构造器注入引用数据类型"></a>5.2.2 构造器注入引用数据类型</h4><p>接下来，在上面这个环境中来完成构造器注入的学习:</p>
<blockquote>
<p>需求：将BookServiceImpl类中的bookDao修改成使用构造器的方式注入。</p>
<p>1.将bookDao的setter方法删除掉</p>
<p>2.添加带有bookDao参数的构造方法</p>
<p>3.在applicationContext.xml中配置</p>
</blockquote>
<h5 id="步骤1-删除setter方法并提供构造方法"><a href="#步骤1-删除setter方法并提供构造方法" class="headerlink" title="步骤1:删除setter方法并提供构造方法"></a>步骤1:删除setter方法并提供构造方法</h5><p>在BookServiceImpl类中将bookDao的setter方法删除掉,并添加带有bookDao参数的构造方法</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">BookServiceImpl</span> <span class="keyword">implements</span> <span class="title class_">BookService</span>&#123;</span><br><span class="line">    <span class="keyword">private</span> BookDao bookDao;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">BookServiceImpl</span><span class="params">(BookDao bookDao)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.bookDao = bookDao;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">save</span><span class="params">()</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;book service save ...&quot;</span>);</span><br><span class="line">        bookDao.save();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h5 id="步骤2-配置文件中进行配置构造方式注入"><a href="#步骤2-配置文件中进行配置构造方式注入" class="headerlink" title="步骤2:配置文件中进行配置构造方式注入"></a>步骤2:配置文件中进行配置构造方式注入</h5><p>在applicationContext.xml中配置</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?xml version=<span class="string">&quot;1.0&quot;</span> encoding=<span class="string">&quot;UTF-8&quot;</span>?&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">beans</span> <span class="attr">xmlns</span>=<span class="string">&quot;http://www.springframework.org/schema/beans&quot;</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xmlns:xsi</span>=<span class="string">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xsi:schemaLocation</span>=<span class="string">&quot;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd&quot;</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;bookDao&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.itheima.dao.impl.BookDaoImpl&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;bookService&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.itheima.service.impl.BookServiceImpl&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">constructor-arg</span> <span class="attr">name</span>=<span class="string">&quot;bookDao&quot;</span> <span class="attr">ref</span>=<span class="string">&quot;bookDao&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">beans</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p><strong>说明:</strong></p>
<p>标签<constructor-arg>中</p>
<ul>
<li><p>name属性对应的值为构造函数中方法形参的参数名，必须要保持一致。</p>
</li>
<li><p>ref属性指向的是spring的IOC容器中其他bean对象。</p>
</li>
</ul>
<h5 id="步骤3：运行程序"><a href="#步骤3：运行程序" class="headerlink" title="步骤3：运行程序"></a>步骤3：运行程序</h5><p>运行AppForDIConstructor类，查看结果，说明bookDao已经成功注入。</p>
<p><img src="/images/1629802656916.png"></p>
<h4 id="5-2-3-构造器注入多个引用数据类型"><a href="#5-2-3-构造器注入多个引用数据类型" class="headerlink" title="5.2.3 构造器注入多个引用数据类型"></a>5.2.3 构造器注入多个引用数据类型</h4><blockquote>
<p>需求:在BookServiceImpl使用构造函数注入多个引用数据类型，比如userDao</p>
<p>1.声明userDao属性</p>
<p>2.生成一个带有bookDao和userDao参数的构造函数</p>
<p>3.在applicationContext.xml中配置注入</p>
</blockquote>
<h5 id="步骤1-提供多个属性的构造函数"><a href="#步骤1-提供多个属性的构造函数" class="headerlink" title="步骤1:提供多个属性的构造函数"></a>步骤1:提供多个属性的构造函数</h5><p>在BookServiceImpl声明userDao并提供多个参数的构造函数</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">BookServiceImpl</span> <span class="keyword">implements</span> <span class="title class_">BookService</span>&#123;</span><br><span class="line">    <span class="keyword">private</span> BookDao bookDao;</span><br><span class="line">    <span class="keyword">private</span> UserDao userDao;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">BookServiceImpl</span><span class="params">(BookDao bookDao,UserDao userDao)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.bookDao = bookDao;</span><br><span class="line">        <span class="built_in">this</span>.userDao = userDao;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">save</span><span class="params">()</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;book service save ...&quot;</span>);</span><br><span class="line">        bookDao.save();</span><br><span class="line">        userDao.save();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>步骤2:配置文件中配置多参数注入</p>
<p>在applicationContext.xml中配置注入</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?xml version=<span class="string">&quot;1.0&quot;</span> encoding=<span class="string">&quot;UTF-8&quot;</span>?&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">beans</span> <span class="attr">xmlns</span>=<span class="string">&quot;http://www.springframework.org/schema/beans&quot;</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xmlns:xsi</span>=<span class="string">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xsi:schemaLocation</span>=<span class="string">&quot;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd&quot;</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;bookDao&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.itheima.dao.impl.BookDaoImpl&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;userDao&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.itheima.dao.impl.UserDaoImpl&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;bookService&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.itheima.service.impl.BookServiceImpl&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">constructor-arg</span> <span class="attr">name</span>=<span class="string">&quot;bookDao&quot;</span> <span class="attr">ref</span>=<span class="string">&quot;bookDao&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">constructor-arg</span> <span class="attr">name</span>=<span class="string">&quot;userDao&quot;</span> <span class="attr">ref</span>=<span class="string">&quot;userDao&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">beans</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>**说明:**这两个<code>&lt;contructor-arg&gt;</code>的配置顺序可以任意</p>
<h5 id="步骤3-运行程序-4"><a href="#步骤3-运行程序-4" class="headerlink" title="步骤3:运行程序"></a>步骤3:运行程序</h5><p>运行AppForDIConstructor类，查看结果，说明userDao已经成功注入。</p>
<p><img src="/images/1629802697318.png"></p>
<h4 id="5-2-4-构造器注入多个简单数据类型"><a href="#5-2-4-构造器注入多个简单数据类型" class="headerlink" title="5.2.4 构造器注入多个简单数据类型"></a>5.2.4 构造器注入多个简单数据类型</h4><blockquote>
<p>需求:在BookDaoImpl中，使用构造函数注入databaseName和connectionNum两个参数。</p>
<p>参考引用数据类型的注入，我们可以推出具体的步骤为:</p>
<p>1.提供一个包含这两个参数的构造方法</p>
<p>2.在applicationContext.xml中进行注入配置</p>
</blockquote>
<h5 id="步骤1-添加多个简单属性并提供构造方法"><a href="#步骤1-添加多个简单属性并提供构造方法" class="headerlink" title="步骤1:添加多个简单属性并提供构造方法"></a>步骤1:添加多个简单属性并提供构造方法</h5><p>修改BookDaoImpl类，添加构造方法</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">BookDaoImpl</span> <span class="keyword">implements</span> <span class="title class_">BookDao</span> &#123;</span><br><span class="line">    <span class="keyword">private</span> String databaseName;</span><br><span class="line">    <span class="keyword">private</span> <span class="type">int</span> connectionNum;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">BookDaoImpl</span><span class="params">(String databaseName, <span class="type">int</span> connectionNum)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.databaseName = databaseName;</span><br><span class="line">        <span class="built_in">this</span>.connectionNum = connectionNum;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">save</span><span class="params">()</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;book dao save ...&quot;</span>+databaseName+<span class="string">&quot;,&quot;</span>+connectionNum);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h5 id="步骤2-配置完成多个属性构造器注入"><a href="#步骤2-配置完成多个属性构造器注入" class="headerlink" title="步骤2:配置完成多个属性构造器注入"></a>步骤2:配置完成多个属性构造器注入</h5><p>在applicationContext.xml中进行注入配置</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?xml version=<span class="string">&quot;1.0&quot;</span> encoding=<span class="string">&quot;UTF-8&quot;</span>?&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">beans</span> <span class="attr">xmlns</span>=<span class="string">&quot;http://www.springframework.org/schema/beans&quot;</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xmlns:xsi</span>=<span class="string">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xsi:schemaLocation</span>=<span class="string">&quot;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd&quot;</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;bookDao&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.itheima.dao.impl.BookDaoImpl&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">constructor-arg</span> <span class="attr">name</span>=<span class="string">&quot;databaseName&quot;</span> <span class="attr">value</span>=<span class="string">&quot;mysql&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">constructor-arg</span> <span class="attr">name</span>=<span class="string">&quot;connectionNum&quot;</span> <span class="attr">value</span>=<span class="string">&quot;666&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;userDao&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.itheima.dao.impl.UserDaoImpl&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;bookService&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.itheima.service.impl.BookServiceImpl&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">constructor-arg</span> <span class="attr">name</span>=<span class="string">&quot;bookDao&quot;</span> <span class="attr">ref</span>=<span class="string">&quot;bookDao&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">constructor-arg</span> <span class="attr">name</span>=<span class="string">&quot;userDao&quot;</span> <span class="attr">ref</span>=<span class="string">&quot;userDao&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">beans</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>**说明:**这两个<code>&lt;contructor-arg&gt;</code>的配置顺序可以任意</p>
<h5 id="步骤3-运行程序-5"><a href="#步骤3-运行程序-5" class="headerlink" title="步骤3:运行程序"></a>步骤3:运行程序</h5><p>运行AppForDIConstructor类，查看结果</p>
<p><img src="/images/1629803111769.png"></p>
<p>上面已经完成了构造函数注入的基本使用，但是会存在一些问题:</p>
<p><img src="/images/1629803529598.png"></p>
<ul>
<li>当构造函数中方法的参数名发生变化后，配置文件中的name属性也需要跟着变</li>
<li>这两块存在紧耦合，具体该如何解决?</li>
</ul>
<p>在解决这个问题之前，需要提前说明的是，这个参数名发生变化的情况并不多，所以上面的还是比较主流的配置方式，下面介绍的，大家都以了解为主。</p>
<p>方式一:删除name属性，添加type属性，按照类型注入</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;bookDao&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.itheima.dao.impl.BookDaoImpl&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">constructor-arg</span> <span class="attr">type</span>=<span class="string">&quot;int&quot;</span> <span class="attr">value</span>=<span class="string">&quot;10&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">constructor-arg</span> <span class="attr">type</span>=<span class="string">&quot;java.lang.String&quot;</span> <span class="attr">value</span>=<span class="string">&quot;mysql&quot;</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br></pre></td></tr></table></figure>

<ul>
<li>这种方式可以解决构造函数形参名发生变化带来的耦合问题</li>
<li>但是如果构造方法参数中有类型相同的参数，这种方式就不太好实现了</li>
</ul>
<p>方式二:删除type属性，添加index属性，按照索引下标注入，下标从0开始</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;bookDao&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.itheima.dao.impl.BookDaoImpl&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">constructor-arg</span> <span class="attr">index</span>=<span class="string">&quot;1&quot;</span> <span class="attr">value</span>=<span class="string">&quot;100&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">constructor-arg</span> <span class="attr">index</span>=<span class="string">&quot;0&quot;</span> <span class="attr">value</span>=<span class="string">&quot;mysql&quot;</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br></pre></td></tr></table></figure>

<ul>
<li>这种方式可以解决参数类型重复问题</li>
<li>但是如果构造方法参数顺序发生变化后，这种方式又带来了耦合问题</li>
</ul>
<p>介绍完两种参数的注入方式，具体我们该如何选择呢?</p>
<ol>
<li>强制依赖使用构造器进行，使用setter注入有概率不进行注入导致null对象出现<ul>
<li>强制依赖指对象在创建的过程中必须要注入指定的参数</li>
</ul>
</li>
<li>可选依赖使用setter注入进行，灵活性强<ul>
<li>可选依赖指对象在创建过程中注入的参数可有可无</li>
</ul>
</li>
<li>Spring框架倡导使用构造器，第三方框架内部大多数采用构造器注入的形式进行数据初始化，相对严谨</li>
<li>如果有必要可以两者同时使用，使用构造器注入完成强制依赖的注入，使用setter注入完成可选依赖的注入</li>
<li>实际开发过程中还要根据实际情况分析，如果受控对象没有提供setter方法就必须使用构造器注入</li>
<li><strong>&#x3D;&#x3D;自己开发的模块推荐使用setter注入&#x3D;&#x3D;</strong></li>
</ol>
<p>这节中主要讲解的是Spring的依赖注入的实现方式:</p>
<ul>
<li><p>setter注入</p>
<ul>
<li><p>简单数据类型</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">...</span>&gt;</span></span><br><span class="line">	<span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;&quot;</span> <span class="attr">value</span>=<span class="string">&quot;&quot;</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br></pre></td></tr></table></figure>
</li>
<li><p>引用数据类型</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">...</span>&gt;</span></span><br><span class="line">	<span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;&quot;</span> <span class="attr">ref</span>=<span class="string">&quot;&quot;</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br></pre></td></tr></table></figure></li>
</ul>
</li>
<li><p>构造器注入</p>
<ul>
<li><p>简单数据类型</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">...</span>&gt;</span></span><br><span class="line">	<span class="tag">&lt;<span class="name">constructor-arg</span> <span class="attr">name</span>=<span class="string">&quot;&quot;</span> <span class="attr">index</span>=<span class="string">&quot;&quot;</span> <span class="attr">type</span>=<span class="string">&quot;&quot;</span> <span class="attr">value</span>=<span class="string">&quot;&quot;</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br></pre></td></tr></table></figure>
</li>
<li><p>引用数据类型</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">...</span>&gt;</span></span><br><span class="line">	<span class="tag">&lt;<span class="name">constructor-arg</span> <span class="attr">name</span>=<span class="string">&quot;&quot;</span> <span class="attr">index</span>=<span class="string">&quot;&quot;</span> <span class="attr">type</span>=<span class="string">&quot;&quot;</span> <span class="attr">ref</span>=<span class="string">&quot;&quot;</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br></pre></td></tr></table></figure></li>
</ul>
</li>
<li><p>依赖注入的方式选择上</p>
<ul>
<li>建议使用setter注入</li>
<li>第三方技术根据情况选择</li>
</ul>
</li>
</ul>
<h3 id="5-3-自动配置"><a href="#5-3-自动配置" class="headerlink" title="5.3 自动配置"></a>5.3 自动配置</h3><p>前面花了大量的时间把Spring的注入去学习了下，总结起来就一个字&#x3D;&#x3D;麻烦&#x3D;&#x3D;。</p>
<p>问:麻烦在哪?</p>
<p>答:配置文件的编写配置上。</p>
<p>问:有更简单方式么?</p>
<p>答:有，自动配置</p>
<p>什么是自动配置以及如何实现自动配置，就是接下来要学习的内容：</p>
<h4 id="5-3-1-什么是依赖自动装配"><a href="#5-3-1-什么是依赖自动装配" class="headerlink" title="5.3.1 什么是依赖自动装配?"></a>5.3.1 什么是依赖自动装配?</h4><ul>
<li>IoC容器根据bean所依赖的资源在容器中自动查找并注入到bean中的过程称为自动装配</li>
</ul>
<h4 id="5-3-2-自动装配方式有哪些"><a href="#5-3-2-自动装配方式有哪些" class="headerlink" title="5.3.2 自动装配方式有哪些?"></a>5.3.2 自动装配方式有哪些?</h4><ul>
<li>&#x3D;&#x3D;按类型（常用）&#x3D;&#x3D;</li>
<li>按名称</li>
<li>按构造方法</li>
<li>不启用自动装配</li>
</ul>
<h4 id="5-3-3-准备下案例环境"><a href="#5-3-3-准备下案例环境" class="headerlink" title="5.3.3 准备下案例环境"></a>5.3.3 准备下案例环境</h4><ul>
<li>创建一个Maven项目</li>
<li>pom.xml添加依赖</li>
<li>resources下添加spring的配置文件</li>
</ul>
<p>这些步骤和前面的都一致，大家可以快速的拷贝即可，最终项目的结构如下:</p>
<p><img src="/images/1629805387647.png"></p>
<p>(1)项目中添加BookDao、BookDaoImpl、BookService和BookServiceImpl类</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">BookDao</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">save</span><span class="params">()</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">BookDaoImpl</span> <span class="keyword">implements</span> <span class="title class_">BookDao</span> &#123;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">private</span> String databaseName;</span><br><span class="line">    <span class="keyword">private</span> <span class="type">int</span> connectionNum;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">save</span><span class="params">()</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;book dao save ...&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">BookService</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">save</span><span class="params">()</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">BookServiceImpl</span> <span class="keyword">implements</span> <span class="title class_">BookService</span>&#123;</span><br><span class="line">    <span class="keyword">private</span> BookDao bookDao;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setBookDao</span><span class="params">(BookDao bookDao)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.bookDao = bookDao;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">save</span><span class="params">()</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;book service save ...&quot;</span>);</span><br><span class="line">        bookDao.save();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>(2)resources下提供spring的配置文件</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?xml version=<span class="string">&quot;1.0&quot;</span> encoding=<span class="string">&quot;UTF-8&quot;</span>?&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">beans</span> <span class="attr">xmlns</span>=<span class="string">&quot;http://www.springframework.org/schema/beans&quot;</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xmlns:xsi</span>=<span class="string">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xsi:schemaLocation</span>=<span class="string">&quot;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd&quot;</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;bookDao&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.itheima.dao.impl.BookDaoImpl&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;bookService&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.itheima.service.impl.BookServiceImpl&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;bookDao&quot;</span> <span class="attr">ref</span>=<span class="string">&quot;bookDao&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">beans</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>(3)编写AppForAutoware运行类，加载Spring的IOC容器，并从中获取对应的bean对象</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">AppForAutoware</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">( String[] args )</span> &#123;</span><br><span class="line">        <span class="type">ApplicationContext</span> <span class="variable">ctx</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ClassPathXmlApplicationContext</span>(<span class="string">&quot;applicationContext.xml&quot;</span>);</span><br><span class="line">        <span class="type">BookService</span> <span class="variable">bookService</span> <span class="operator">=</span> (BookService) ctx.getBean(<span class="string">&quot;bookService&quot;</span>);</span><br><span class="line">        bookService.save();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h4 id="5-3-4-完成自动装配的配置"><a href="#5-3-4-完成自动装配的配置" class="headerlink" title="5.3.4 完成自动装配的配置"></a>5.3.4 完成自动装配的配置</h4><p>接下来，在上面这个环境中来完成<code>自动装配</code>的学习:</p>
<p>自动装配只需要修改applicationContext.xml配置文件即可:</p>
<p>(1)将<code>&lt;property&gt;</code>标签删除</p>
<p>(2)在<code>&lt;bean&gt;</code>标签中添加autowire属性</p>
<p>首先来实现按照类型注入的配置</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?xml version=<span class="string">&quot;1.0&quot;</span> encoding=<span class="string">&quot;UTF-8&quot;</span>?&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">beans</span> <span class="attr">xmlns</span>=<span class="string">&quot;http://www.springframework.org/schema/beans&quot;</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xmlns:xsi</span>=<span class="string">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xsi:schemaLocation</span>=<span class="string">&quot;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd&quot;</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">class</span>=<span class="string">&quot;com.itheima.dao.impl.BookDaoImpl&quot;</span>/&gt;</span></span><br><span class="line">    <span class="comment">&lt;!--autowire属性：开启自动装配，通常使用按类型装配--&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;bookService&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.itheima.service.impl.BookServiceImpl&quot;</span> <span class="attr">autowire</span>=<span class="string">&quot;byType&quot;</span>/&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;/<span class="name">beans</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>&#x3D;&#x3D;注意事项:&#x3D;&#x3D;</p>
<ul>
<li>需要注入属性的类中对应属性的setter方法不能省略</li>
<li>被注入的对象必须要被Spring的IOC容器管理</li>
<li>按照类型在Spring的IOC容器中如果找到多个对象，会报<code>NoUniqueBeanDefinitionException</code></li>
</ul>
<p>一个类型在IOC中有多个对象，还想要注入成功，这个时候就需要按照名称注入，配置方式为:</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?xml version=<span class="string">&quot;1.0&quot;</span> encoding=<span class="string">&quot;UTF-8&quot;</span>?&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">beans</span> <span class="attr">xmlns</span>=<span class="string">&quot;http://www.springframework.org/schema/beans&quot;</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xmlns:xsi</span>=<span class="string">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xsi:schemaLocation</span>=<span class="string">&quot;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd&quot;</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">class</span>=<span class="string">&quot;com.itheima.dao.impl.BookDaoImpl&quot;</span>/&gt;</span></span><br><span class="line">    <span class="comment">&lt;!--autowire属性：开启自动装配，通常使用按类型装配--&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;bookService&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.itheima.service.impl.BookServiceImpl&quot;</span> <span class="attr">autowire</span>=<span class="string">&quot;byName&quot;</span>/&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;/<span class="name">beans</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>&#x3D;&#x3D;注意事项:&#x3D;&#x3D;</p>
<ul>
<li><p>按照名称注入中的名称指的是什么?</p>
<p><img src="/images/1629806856156.png"></p>
<ul>
<li>bookDao是private修饰的，外部类无法直接方法</li>
<li>外部类只能通过属性的set方法进行访问</li>
<li>对外部类来说，setBookDao方法名，去掉set后首字母小写是其属性名<ul>
<li>为什么是去掉set首字母小写?</li>
<li>这个规则是set方法生成的默认规则，set方法的生成是把属性名首字母大写前面加set形成的方法名</li>
</ul>
</li>
<li>所以按照名称注入，其实是和对应的set方法有关，但是如果按照标准起名称，属性名和set对应的名是一致的</li>
</ul>
</li>
<li><p>如果按照名称去找对应的bean对象，找不到则注入Null</p>
</li>
<li><p>当某一个类型在IOC容器中有多个对象，按照名称注入只找其指定名称对应的bean对象，不会报错</p>
</li>
</ul>
<p>两种方式介绍完后，以后用的更多的是&#x3D;&#x3D;按照类型&#x3D;&#x3D;注入。</p>
<p>最后对于依赖注入，需要注意一些其他的配置特征:</p>
<ol>
<li>自动装配用于引用类型依赖注入，不能对简单类型进行操作</li>
<li>使用按类型装配时（byType）必须保障容器中相同类型的bean唯一，推荐使用</li>
<li>使用按名称装配时（byName）必须保障容器中具有指定名称的bean，因变量名与配置耦合，不推荐使用</li>
<li>自动装配优先级低于setter注入与构造器注入，同时出现时自动装配配置失效</li>
</ol>
<h3 id="5-4-集合注入"><a href="#5-4-集合注入" class="headerlink" title="5.4 集合注入"></a>5.4 集合注入</h3><p>前面我们已经能完成引入数据类型和简单数据类型的注入，但是还有一种数据类型&#x3D;&#x3D;集合&#x3D;&#x3D;，集合中既可以装简单数据类型也可以装引用数据类型，对于集合，在Spring中该如何注入呢?</p>
<p>先来回顾下，常见的集合类型有哪些?</p>
<ul>
<li>数组</li>
<li>List</li>
<li>Set</li>
<li>Map</li>
<li>Properties</li>
</ul>
<p>针对不同的集合类型，该如何实现注入呢?</p>
<h4 id="5-4-1-环境准备"><a href="#5-4-1-环境准备" class="headerlink" title="5.4.1 环境准备"></a>5.4.1 环境准备</h4><ul>
<li>创建一个Maven项目</li>
<li>pom.xml添加依赖</li>
<li>resources下添加spring的配置文件applicationContext.xml</li>
</ul>
<p>这些步骤和前面的都一致，大家可以快速的拷贝即可，最终项目的结构如下:</p>
<p><img src="/images/1629807579330.png"></p>
<p>(1)项目中添加添加BookDao、BookDaoImpl类</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">BookDao</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">save</span><span class="params">()</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">BookDaoImpl</span> <span class="keyword">implements</span> <span class="title class_">BookDao</span> &#123;</span><br><span class="line">    </span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">BookDaoImpl</span> <span class="keyword">implements</span> <span class="title class_">BookDao</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="type">int</span>[] array;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> List&lt;String&gt; list;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> Set&lt;String&gt; set;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> Map&lt;String,String&gt; map;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> Properties properties;</span><br><span class="line"></span><br><span class="line">     <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">save</span><span class="params">()</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;book dao save ...&quot;</span>);</span><br><span class="line"></span><br><span class="line">        System.out.println(<span class="string">&quot;遍历数组:&quot;</span> + Arrays.toString(array));</span><br><span class="line"></span><br><span class="line">        System.out.println(<span class="string">&quot;遍历List&quot;</span> + list);</span><br><span class="line"></span><br><span class="line">        System.out.println(<span class="string">&quot;遍历Set&quot;</span> + set);</span><br><span class="line"></span><br><span class="line">        System.out.println(<span class="string">&quot;遍历Map&quot;</span> + map);</span><br><span class="line"></span><br><span class="line">        System.out.println(<span class="string">&quot;遍历Properties&quot;</span> + properties);</span><br><span class="line">    &#125;</span><br><span class="line">	<span class="comment">//setter....方法省略，自己使用工具生成</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>(2)resources下提供spring的配置文件，applicationContext.xml</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?xml version=<span class="string">&quot;1.0&quot;</span> encoding=<span class="string">&quot;UTF-8&quot;</span>?&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">beans</span> <span class="attr">xmlns</span>=<span class="string">&quot;http://www.springframework.org/schema/beans&quot;</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xmlns:xsi</span>=<span class="string">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xsi:schemaLocation</span>=<span class="string">&quot;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd&quot;</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;bookDao&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.itheima.dao.impl.BookDaoImpl&quot;</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">beans</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>(3)编写AppForDICollection运行类，加载Spring的IOC容器，并从中获取对应的bean对象</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">AppForDICollection</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">( String[] args )</span> &#123;</span><br><span class="line">        <span class="type">ApplicationContext</span> <span class="variable">ctx</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ClassPathXmlApplicationContext</span>(<span class="string">&quot;applicationContext.xml&quot;</span>);</span><br><span class="line">        <span class="type">BookDao</span> <span class="variable">bookDao</span> <span class="operator">=</span> (BookDao) ctx.getBean(<span class="string">&quot;bookDao&quot;</span>);</span><br><span class="line">        bookDao.save();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>接下来，在上面这个环境中来完成<code>集合注入</code>的学习:</p>
<p>下面的所以配置方式，都是在bookDao的bean标签中使用<property>进行注入</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?xml version=<span class="string">&quot;1.0&quot;</span> encoding=<span class="string">&quot;UTF-8&quot;</span>?&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">beans</span> <span class="attr">xmlns</span>=<span class="string">&quot;http://www.springframework.org/schema/beans&quot;</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xmlns:xsi</span>=<span class="string">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xsi:schemaLocation</span>=<span class="string">&quot;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd&quot;</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;bookDao&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.itheima.dao.impl.BookDaoImpl&quot;</span>&gt;</span></span><br><span class="line">        </span><br><span class="line">    <span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">beans</span>&gt;</span></span><br></pre></td></tr></table></figure>

<h4 id="5-4-2-注入数组类型数据"><a href="#5-4-2-注入数组类型数据" class="headerlink" title="5.4.2 注入数组类型数据"></a>5.4.2 注入数组类型数据</h4><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;array&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">array</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">value</span>&gt;</span>100<span class="tag">&lt;/<span class="name">value</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">value</span>&gt;</span>200<span class="tag">&lt;/<span class="name">value</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">value</span>&gt;</span>300<span class="tag">&lt;/<span class="name">value</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">array</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br></pre></td></tr></table></figure>

<h4 id="5-4-3-注入List类型数据"><a href="#5-4-3-注入List类型数据" class="headerlink" title="5.4.3 注入List类型数据"></a>5.4.3 注入List类型数据</h4><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;list&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">list</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">value</span>&gt;</span>itcast<span class="tag">&lt;/<span class="name">value</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">value</span>&gt;</span>itheima<span class="tag">&lt;/<span class="name">value</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">value</span>&gt;</span>boxuegu<span class="tag">&lt;/<span class="name">value</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">value</span>&gt;</span>chuanzhihui<span class="tag">&lt;/<span class="name">value</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">list</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br></pre></td></tr></table></figure>

<h4 id="5-4-4-注入Set类型数据"><a href="#5-4-4-注入Set类型数据" class="headerlink" title="5.4.4 注入Set类型数据"></a>5.4.4 注入Set类型数据</h4><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;set&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">set</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">value</span>&gt;</span>itcast<span class="tag">&lt;/<span class="name">value</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">value</span>&gt;</span>itheima<span class="tag">&lt;/<span class="name">value</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">value</span>&gt;</span>boxuegu<span class="tag">&lt;/<span class="name">value</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">value</span>&gt;</span>boxuegu<span class="tag">&lt;/<span class="name">value</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">set</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br></pre></td></tr></table></figure>

<h4 id="5-4-5-注入Map类型数据"><a href="#5-4-5-注入Map类型数据" class="headerlink" title="5.4.5 注入Map类型数据"></a>5.4.5 注入Map类型数据</h4><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;map&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">map</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">entry</span> <span class="attr">key</span>=<span class="string">&quot;country&quot;</span> <span class="attr">value</span>=<span class="string">&quot;china&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">entry</span> <span class="attr">key</span>=<span class="string">&quot;province&quot;</span> <span class="attr">value</span>=<span class="string">&quot;henan&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">entry</span> <span class="attr">key</span>=<span class="string">&quot;city&quot;</span> <span class="attr">value</span>=<span class="string">&quot;kaifeng&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">map</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br></pre></td></tr></table></figure>

<h4 id="5-4-6-注入Properties类型数据"><a href="#5-4-6-注入Properties类型数据" class="headerlink" title="5.4.6 注入Properties类型数据"></a>5.4.6 注入Properties类型数据</h4><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;properties&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">props</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">prop</span> <span class="attr">key</span>=<span class="string">&quot;country&quot;</span>&gt;</span>china<span class="tag">&lt;/<span class="name">prop</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">prop</span> <span class="attr">key</span>=<span class="string">&quot;province&quot;</span>&gt;</span>henan<span class="tag">&lt;/<span class="name">prop</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">prop</span> <span class="attr">key</span>=<span class="string">&quot;city&quot;</span>&gt;</span>kaifeng<span class="tag">&lt;/<span class="name">prop</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">props</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>配置完成后，运行下看结果:</p>
<p><img src="/images/1629808046783.png"></p>
<p><strong>说明：</strong></p>
<ul>
<li>property标签表示setter方式注入，构造方式注入constructor-arg标签内部也可以写<code>&lt;array&gt;</code>、<code>&lt;list&gt;</code>、<code>&lt;set&gt;</code>、<code>&lt;map&gt;</code>、<code>&lt;props&gt;</code>标签</li>
<li>List的底层也是通过数组实现的，所以<code>&lt;list&gt;</code>和<code>&lt;array&gt;</code>标签是可以混用</li>
<li>集合中要添加引用类型，只需要把<code>&lt;value&gt;</code>标签改成<code>&lt;ref&gt;</code>标签，这种方式用的比较少</li>
</ul>

      
    </div>

    
    
    
      <footer class="post-footer">
        <div class="post-eof"></div>
      </footer>
  </article>
  
  
  

      
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://daorongxing.gitee.io/post/370/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="Daorong Xing">
      <meta itemprop="description" content="这是我的个人博客，记录计算机学习之路！">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="邢道荣的个人博客">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          
            <a href="/post/370/" class="post-title-link" itemprop="url">GC</a>
        </h2>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>

              <time title="创建时间：2022-11-25 18:50:12" itemprop="dateCreated datePublished" datetime="2022-11-25T18:50:12+08:00">2022-11-25</time>
            </span>
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="far fa-calendar-check"></i>
                </span>
                <span class="post-meta-item-text">更新于</span>
                <time title="修改时间：2022-11-30 16:55:22" itemprop="dateModified" datetime="2022-11-30T16:55:22+08:00">2022-11-30</time>
              </span>
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-folder"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/JVM/" itemprop="url" rel="index"><span itemprop="name">JVM</span></a>
                </span>
            </span>

          <br>
            <span class="post-meta-item" title="本文字数">
              <span class="post-meta-item-icon">
                <i class="far fa-file-word"></i>
              </span>
                <span class="post-meta-item-text">本文字数：</span>
              <span>9.6k</span>
            </span>
            <span class="post-meta-item" title="阅读时长">
              <span class="post-meta-item-icon">
                <i class="far fa-clock"></i>
              </span>
                <span class="post-meta-item-text">阅读时长 &asymp;</span>
              <span>9 分钟</span>
            </span>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
          <h1 id="1-如何判断对象可以被回收"><a href="#1-如何判断对象可以被回收" class="headerlink" title="1. 如何判断对象可以被回收"></a>1. 如何判断对象可以被回收</h1><h2 id="1-1-引用计数法"><a href="#1-1-引用计数法" class="headerlink" title="1.1 引用计数法"></a>1.1 引用计数法</h2><p>通过调用对象的次数计数，调用了一次+1，调用了两次+2；<br>弊端：循环引用可能导致计数次数无法归零，进而导致内存泄漏。</p>
<h2 id="1-2-可达性分析算法"><a href="#1-2-可达性分析算法" class="headerlink" title="1.2 可达性分析算法"></a>1.2 可达性分析算法</h2><p>先确立一个根对象(<code>GC Root</code>)，看有没有对象和根对象直接或者间接的引用，如果有，那就是不能被垃圾回收的对象。<br>可作为<code>GC Root</code>对象的有：</p>
<ul>
<li>方法堆栈中的参数，局部变量，临时变量等</li>
<li>引用类型的静态变量</li>
<li>字符串常量池中的引用</li>
<li>本地方法栈中引用的对象</li>
<li>Class对象，异常对象，系统类加载器，本地代码缓存等</li>
</ul>
<h2 id="1-3-四种引用"><a href="#1-3-四种引用" class="headerlink" title="1.3 四种引用"></a>1.3 四种引用</h2><h3 id="1-3-1-强引用"><a href="#1-3-1-强引用" class="headerlink" title="1.3.1 强引用"></a>1.3.1 强引用</h3><p>沿着根对象能找到的A对象，那么A对象称为被强引用。仅当强引用与A对象断开时，可被回收。<br></p>
<h3 id="1-3-2-软引用"><a href="#1-3-2-软引用" class="headerlink" title="1.3.2 软引用"></a>1.3.2 软引用</h3><p><code>SoftRenference&lt;byte[]&gt; ref = new SoftRenference&lt;&gt;(new byte[])</code><br><strong>没有被强引用所引用</strong>，垃圾回收发生时都<u>有可能</u>被回收。<br>当发生过一次垃圾回收且内存仍然不够时，会回收<strong>被软引用引用的对象</strong>。<br>软引用一般适用于一些非必要的场景，比如说网页图片，没有必要一直占着内存空间，等到需要的时候再加载就可以了。</p>
<ul>
<li>具体案例如下：<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">soft</span><span class="params">()</span> &#123;</span><br><span class="line">    <span class="comment">// list --&gt; SoftReference --&gt; byte[]</span></span><br><span class="line"></span><br><span class="line">    List&lt;SoftReference&lt;<span class="type">byte</span>[]&gt;&gt; list = <span class="keyword">new</span> <span class="title class_">ArrayList</span>&lt;&gt;();</span><br><span class="line">    <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">0</span>; i &lt; <span class="number">5</span>; i++) &#123;</span><br><span class="line">        SoftReference&lt;<span class="type">byte</span>[]&gt; ref = <span class="keyword">new</span> <span class="title class_">SoftReference</span>&lt;&gt;(<span class="keyword">new</span> <span class="title class_">byte</span>[_4MB]);</span><br><span class="line">        System.out.println(ref.get());</span><br><span class="line">        list.add(ref);</span><br><span class="line">        System.out.println(list.size());</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">    System.out.println(<span class="string">&quot;循环结束：&quot;</span> + list.size());</span><br><span class="line">    <span class="keyword">for</span> (SoftReference&lt;<span class="type">byte</span>[]&gt; ref : list) &#123;</span><br><span class="line">        System.out.println(ref.get());</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<strong>输出结果：</strong><blockquote>
<p>[B@330bedb4<br>1<br>[B@2503dbd3<br>2<br>[B@4b67cf4d<br>3<br>[GC (Allocation Failure) [PSYoungGen: 2162K-&gt;488K(6144K)] 14450K-&gt;13074K(19968K), 0.0019161 secs] [Times: user&#x3D;0.00 sys&#x3D;0.00, real&#x3D;0.00 secs]<br><mark>内存不足，进行一次垃圾回收。</mark><br>[B@7ea987ac<br>4<br>[GC (Allocation Failure) –[PSYoungGen: 4696K-&gt;4696K(6144K)] 17282K-&gt;17290K(19968K), 0.0006865 secs] [Times: user&#x3D;0.00 sys&#x3D;0.00, real&#x3D;0.00 secs]<br>[Full GC (Ergonomics) [PSYoungGen: 4696K-&gt;4535K(6144K)] [ParOldGen: 12594K-&gt;12545K(13824K)] 17290K-&gt;17080K(19968K), [Metaspace: 3373K-&gt;3373K(1056768K)], 0.&gt; &gt; 0045075 secs] [Times: user&#x3D;0.00 sys&#x3D;0.00, real&#x3D;0.01 secs]<br>[GC (Allocation Failure) –[PSYoungGen: 4535K-&gt;4535K(6144K)] 17080K-&gt;17096K(19968K), 0.0006433 secs] [Times: user&#x3D;0.00 sys&#x3D;0.00, real&#x3D;0.00 secs]<br>[Full GC (Allocation Failure) [PSYoungGen: 4535K-&gt;0K(6144K)] [ParOldGen: 12561K-&gt;677K(8704K)] 17096K-&gt;677K(14848K), [Metaspace: 3373K-&gt;3373K(1056768K)], 0.&gt; &gt; 0059614 secs] [Times: user&#x3D;0.01 sys&#x3D;0.00, real&#x3D;0.01 secs]<br><mark>进行一次垃圾回收之后内存仍然不足，触发软引用机制，将软引用创建的对象所垃圾回收释放空间。</mark><br>[B@12a3a380<br>5<br>循环结束：5<br>null<br>null<br>null<br>null<br>[B@12a3a380</p>
</blockquote>
</li>
</ul>
<h3 id="1-3-3-引用队列"><a href="#1-3-3-引用队列" class="headerlink" title="1.3.3 引用队列"></a>1.3.3 引用队列</h3><p>软弱引用无引用对象时，自动进入引用队列</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">int</span> <span class="variable">_4MB</span> <span class="operator">=</span> <span class="number">4</span> * <span class="number">1024</span> * <span class="number">1024</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">    List&lt;SoftReference&lt;<span class="type">byte</span>[]&gt;&gt; list = <span class="keyword">new</span> <span class="title class_">ArrayList</span>&lt;&gt;();</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 引用队列</span></span><br><span class="line">    ReferenceQueue&lt;<span class="type">byte</span>[]&gt; queue = <span class="keyword">new</span> <span class="title class_">ReferenceQueue</span>&lt;&gt;();</span><br><span class="line"></span><br><span class="line">    <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">0</span>; i &lt; <span class="number">5</span>; i++) &#123;</span><br><span class="line">        <span class="comment">// 关联了引用队列， 当软引用所关联的 byte[]被回收时，软引用自己会加入到 queue 中去</span></span><br><span class="line">        SoftReference&lt;<span class="type">byte</span>[]&gt; ref = <span class="keyword">new</span> <span class="title class_">SoftReference</span>&lt;&gt;(<span class="keyword">new</span> <span class="title class_">byte</span>[_4MB], queue);</span><br><span class="line">        System.out.println(ref.get());</span><br><span class="line">        list.add(ref);</span><br><span class="line">        System.out.println(list.size());</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 从队列中获取无用的 软引用对象，并移除</span></span><br><span class="line">    Reference&lt;? <span class="keyword">extends</span> <span class="title class_">byte</span>[]&gt; poll = queue.poll();</span><br><span class="line">    <span class="keyword">while</span>( poll != <span class="literal">null</span>) &#123;</span><br><span class="line">        list.remove(poll);</span><br><span class="line">        poll = queue.poll();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    System.out.println(<span class="string">&quot;===========================&quot;</span>);</span><br><span class="line">    <span class="keyword">for</span> (SoftReference&lt;<span class="type">byte</span>[]&gt; reference : list) &#123;</span><br><span class="line">        System.out.println(reference.get());</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>输出：</p>
<blockquote>
<p>[B@4aa8f0b4 (最后结果)</p>
</blockquote>
<h3 id="1-3-4-弱引用"><a href="#1-3-4-弱引用" class="headerlink" title="1.3.4 弱引用"></a>1.3.4 弱引用</h3><p>只要当发生了垃圾回收，被<strong>弱引用引用的对象</strong>会被回收。<br>类似于软引用。</p>
<h3 id="1-3-5-虚引用"><a href="#1-3-5-虚引用" class="headerlink" title="1.3.5 虚引用"></a>1.3.5 虚引用</h3><p>必须配合引用队列来使用。创建时即关联引用队列。缓存时会留下直接内存，当<code>StringBuffer</code>对象被回收时，他的直接内存没有被回收掉，此时虚引用对象进入引用队列，调用线程清理直接内存。</p>
<h3 id="1-3-6-终结器引用"><a href="#1-3-6-终结器引用" class="headerlink" title="1.3.6 终结器引用"></a>1.3.6 终结器引用</h3><p>当<code>finallize()</code>将要被垃圾回收时，将终结器引用放入引用队列，由<code>finallizeHandler</code>去由终结器引用的对象去销毁对象<br>缺点：<code>finallizeHandler</code>优先级很低，且销毁流程漫长，需要两次GC才能销毁完成，易造成内存泄漏 。</p>
<h1 id="2-三种垃圾收集算法"><a href="#2-三种垃圾收集算法" class="headerlink" title="2. 三种垃圾收集算法"></a>2. 三种垃圾收集算法</h1><h2 id="2-1-标记——清除算法"><a href="#2-1-标记——清除算法" class="headerlink" title="2.1 标记——清除算法"></a>2.1 标记——清除算法</h2><ul>
<li>流程：首先标记出需要垃圾回收的对象，标记完成后，统一回收被标记的对象。也可以相反。</li>
<li>缺点：<br>执行效率不稳定，随着对象增长降低效率不断变化；<br>内存空间碎片化，需要分配较大内存时无法找到足够连续内存不得不提前进行一次垃圾回收操作。<br><img src="/images/Mark-Sweep.png"></li>
</ul>
<h2 id="2-2-标记——复制算法"><a href="#2-2-标记——复制算法" class="headerlink" title="2.2 标记——复制算法"></a>2.2 标记——复制算法</h2><ul>
<li>流程：<strong>半区复制。</strong> 将可用内存按容量划分为大小相等的两块，每次只使用其中的一块，这一块的内存用完了，就将存活着的对象复制到另一块的上面，然后再把已使用的内存空间一次性清理掉。</li>
<li>优点：解决了碎片空间的问题，只需要移动栈顶指针，按顺序分配即可</li>
<li>缺点：内存缩小到原来的一半，造成空间浪费<br><img src="/images/Mark-Copy.png"></li>
</ul>
<p>拓展：APPel式回收<br>把新生代分为一块较大的Eden空间和两块较小的Survivor空间，每次分配内存只使用一块Eden和一块Survivor。发生垃圾收集时，将Eden和Survivor仍然存活的对象一次性复制到另一块Survivor中，直接清理掉原来的两块对象。<br><img src="/images/Appel.png"></p>
<blockquote>
<p>理论依据：HotSpot默认Eden和Survivor的大小比为8：1，即新生代内存空间占总内存空间的90%，相比于标记复制算法节约了巨大的内存空间，而“朝生夕灭”理论认为，新生代中有98%的对象熬不过第一轮收集，所以内存空间时绰绰有余的。</p>
</blockquote>
<h2 id="2-3-标记——整理算法"><a href="#2-3-标记——整理算法" class="headerlink" title="2.3 标记——整理算法"></a>2.3 标记——整理算法</h2><ul>
<li>流程：标记算法和前两者一样，而在回收的时候不同于前者，是先让所有存活的对象往内存空间的一侧进行移动，然后直接清理掉边界之外的内存。</li>
<li>缺点：移动更新对象任务量及其庞大，需要全程暂停用户应用程序才能进行。易形成<code>Stop The World</code>现象。</li>
<li>移动和不移动的利弊比较：<br>是否移动对象都存在弊端，<strong>移动则内存回收</strong>时会更复杂，<strong>不移动则内存分配</strong>时会更复杂；从<strong>垃圾收集的停顿时间</strong>来看，<strong>不移动</strong>对象停顿时间会更短，甚至可以不需要停顿，但是从整个<strong>程序的吞吐量</strong>来看，<strong>移动对象会更划算</strong>；即使不移动对象会使得收集器的效率提升一些，但因内存分配和访问相比垃圾收集频率要 高得多，这部分的耗时增加，总吞吐量仍然是下降的</li>
</ul>
<h2 id="3-垃圾分代回收"><a href="#3-垃圾分代回收" class="headerlink" title="3. 垃圾分代回收"></a>3. 垃圾分代回收</h2><h2 id="3-1-分代垃圾回收机制"><a href="#3-1-分代垃圾回收机制" class="headerlink" title="3.1 分代垃圾回收机制"></a>3.1 分代垃圾回收机制</h2><p><img src="/images/GC.png"></p>
<ul>
<li>对象首先分配在伊甸园区域</li>
<li>新生代空间不足时，触发 minor gc，伊甸园和 from 存活的对象使用 copy 复制到 to 中，存活的对象年龄加 1并且交换 from to。</li>
<li>minor gc 会引发 stop the world，暂停其它用户的线程，等垃圾回收结束，用户线程才恢复运行</li>
<li>当对象寿命超过阈值时，会晋升至老年代，最大寿命是15（4bit）。</li>
<li>当老年代空间不足，会先尝试触发 minor gc，如果之后空间仍不足，那么触发 full gc，STW的时间更长。</li>
<li>当新生代内存无法容纳对象大小，直接晋升为老年代</li>
<li>线程中出现OOM异常时，他占据的内存资源会全部释放掉，不会影响其他线程的运行</li>
</ul>
<h2 id="3-2-VM相关参数"><a href="#3-2-VM相关参数" class="headerlink" title="3.2 VM相关参数"></a>3.2 VM相关参数</h2><p><img src="/images/VMparams.png"></p>
<h1 id="4-垃圾回收器"><a href="#4-垃圾回收器" class="headerlink" title="4. 垃圾回收器"></a>4. 垃圾回收器</h1><blockquote>
<p>serial: 串行    单线程,一个方法执行完下个方法才能够执行<br>parallel : 并行   多线程,可以同时执行垃圾回收, 但其他无法方法运行 STW 相当于所有线程都归垃圾回收所有<br>concurrent : 并发   多线程,其他方法和垃圾回收可以同时执行,但是只能逐个进行垃圾回收,相当于平等的线程分配给每一个方法</p>
</blockquote>
<h2 id="4-1-串行垃圾回收器-Serial-x2F-Serial-Old"><a href="#4-1-串行垃圾回收器-Serial-x2F-Serial-Old" class="headerlink" title="4.1 串行垃圾回收器(Serial&#x2F; Serial Old)"></a>4.1 串行垃圾回收器(Serial&#x2F; Serial Old)</h2><p>单线程。适用于堆内存较少的情况，适合个人电脑<br><code>-XX:+UseSerialGC = Serial + SerialOld</code><br><img src="/images/serial.png"></p>
<h2 id="4-2-吞吐量优先-Parallel-x2F-Parallel-Old"><a href="#4-2-吞吐量优先-Parallel-x2F-Parallel-Old" class="headerlink" title="4.2 吞吐量优先(Parallel&#x2F; Parallel Old)"></a>4.2 吞吐量优先(Parallel&#x2F; Parallel Old)</h2><p>多线程，堆内存较大，多核CPU<br>单位时间内,完成STW次数越少(STW的时间占总用户时间)<br><code>XX:+UseparalellGC</code><br><code>-XX:ParallelGCThreads:n</code> :允许同时允许的线程数量<br><code>-XX:+UseAdaptSizePolicy</code> :自适应调整新生代的大小<br><code>-XX:GCTimeRadio:radio</code> : 最多允许<strong>垃圾回收时间占总线程时间</strong>的<mark>1&#x2F;(1+radio)</mark>,希望堆大<br><code>-XX:MaxGCPauseMillis=is</code> : default是200ms,表示<strong>最长垃圾回收时间</strong>,希望堆小,与上一个冲突</p>
<h2 id="4-2-响应时间优先-CMS-Concurrent-Marking-Sweep"><a href="#4-2-响应时间优先-CMS-Concurrent-Marking-Sweep" class="headerlink" title="4.2 响应时间优先(CMS Concurrent Marking Sweep)"></a>4.2 响应时间优先(CMS Concurrent Marking Sweep)</h2><p>多线程，堆内存较大，多核CPU<br>注重STW时间的长度(单独只考虑STW的时间)</p>
<ul>
<li>初始标记: 需要STW，但仅标记与GC Root关联的对象,速度快</li>
<li>并发标记: 从GC Root直接关联对象开始遍历整个对象图, 耗时长,但并发运行</li>
<li>重新标记: 需要STW, 修正因并发导致的对象标记变动</li>
<li>并发清除: 清理标记对象<br><strong><font color=red>只有在初始标记和重新标记时候才会STW</font></strong><br>三个缺点:</li>
<li>对CPU占用低,只占用了一部分进行GC, 但拖慢了用户进行的CPU量, 对吞吐量有影响.</li>
<li>并发过程中产生的浮动垃圾难以处理</li>
<li>大量空间碎片的产生<br><code>-XX:+UseConcMarkSweepGC</code><br><code>-XX:ConcGCThreads=thread</code>:运用于垃圾回收的线程,一般是总线程数的1&#x2F;4<br><code>-XX:CMSInitiatingOccupancyFraction : percent</code> :触发垃圾回收阈值<br>剩下内存空间留给其他进行的进程以及浮动垃圾; 阈值过高可能导致并发失败<br><img src="/images/CMS.png"></li>
</ul>
<h1 id="5-G1"><a href="#5-G1" class="headerlink" title="5. G1"></a>5. G1</h1><blockquote>
<p>难点，一款很多知识点的垃圾回收器，牵涉到很多新概念</p>
</blockquote>
<h2 id="5-1-基础概念的了解"><a href="#5-1-基础概念的了解" class="headerlink" title="5.1 基础概念的了解"></a>5.1 基础概念的了解</h2><h3 id="5-1-1-写屏障"><a href="#5-1-1-写屏障" class="headerlink" title="5.1.1 写屏障"></a>5.1.1 写屏障</h3><p>可以看成是虚拟机层面对”引用类型字段赋值”这个动作的AOP切面, 在引用对象赋值的时候会形成一个环形,供程序执行额外的操作,而我们解决这种想要在编译场景中赋值的操作,就可以使用写屏障这种在机械码方面操作的手段,简单的来说,写屏障就是负责对在编译阶段中产生改变内容的处理的.</p>
<h3 id="5-1-2-记忆集和卡表"><a href="#5-1-2-记忆集和卡表" class="headerlink" title="5.1.2 记忆集和卡表"></a>5.1.2 记忆集和卡表</h3><p>这两者的出现是为了解决对象跨代引用所带来的问题的.跨代引用会导致老年代向新生代的引用难以通过只扫描新生代的对象去识别, 而如果要进行对老年代和新生代进行同时扫描的话, 那么STW的时间会变长, 性能较差.而记忆集是一种抽象的数据结构, 主要是用于记录非搜集区域指向搜集区域的指针集合的抽象数据结构.其在G1垃圾处理器中被安排在新生代中.而卡表是记忆集的一种具体实现.卡表主要运用在老年代, 当有一个老年代对象引用了新生代的时候, 卡表就会在对应的数组元素值标记为1, 表示这个元素为脏.之后通过写屏障在引用对象的行为发生时进行标记, 之后在新生代垃圾回收扫描时,这个对象就会被视为活对象了.</p>
<h2 id="5-2-三色标记算法"><a href="#5-2-三色标记算法" class="headerlink" title="5.2 三色标记算法"></a>5.2 三色标记算法</h2><h3 id="5-2-1-基本概念"><a href="#5-2-1-基本概念" class="headerlink" title="5.2.1 基本概念"></a>5.2.1 基本概念</h3><p>这是垃圾回收在新生代回收时根据GC Root的遍历所进行标记的一种算法.具体实现为将对象标为黑灰白三种对象, 其划分标准如下: </p>
<ul>
<li>黑: 已经被垃圾回收器访问过, 其所有引用已经全部被扫描过了, 保证其是安全存活的, 且不会再进行扫描;</li>
<li>灰: 被垃圾回收器访问过, 但是他身上的至少一个引用还没有被垃圾回收器访问, 是扫描引用他的灰色对象之后形成的;</li>
<li>白: 没有被垃圾回收器访问过, 开始的时候所有对象都是白色的, 当垃圾回收扫描完成时, 还是白色的对象说明对象是不可达的.<br>扫描完成的标志: 没有灰色对象的存在</li>
</ul>
<h3 id="5-2-2-遍历过程"><a href="#5-2-2-遍历过程" class="headerlink" title="5.2.2 遍历过程"></a>5.2.2 遍历过程</h3><p>1.初始时，全部对象都是白色的<br>2.GC Roots直接引用的对象变成灰色<br>3.从灰色集合中获取元素：<br>    3.1 将本对象直接引用的对象标记为灰色<br>    3.2 将本对象标记为黑色<br>4.重复步骤3，直到灰色的对象集合变为空<br>5.结束后，仍然被标记为白色的对象就是不可达对象，视为垃圾对象</p>
<h3 id="5-2-3-存在问题"><a href="#5-2-3-存在问题" class="headerlink" title="5.2.3 存在问题"></a>5.2.3 存在问题</h3><p>标记算法存在的问题都是基于并发执行下产生的, 因为用户线程在进行的时候, 对象的调用总是会进行, 而同时进行对对象的操作有可能导致引用的错误.</p>
<ol>
<li>漏删<br>把原本死亡的对象标记为存活, 会发生的情况为因为A到B的引用,B被标灰了,但之后引用就断开了, 此时B没有对象引用他, 但是他的标记是灰色, 不会被回收, 这种我们把它叫做浮动垃圾. 这种解决方案十分简单, 下次扫描的时候, 因为没有对象引用他, 他就会自动被删除的.</li>
<li>多删<br>原本是黑色的对象被标记为白色.具体造成原因为如下两点:</li>
</ol>
<ul>
<li>插入了一条或者多条黑色对象对白色对象的引用</li>
<li>删除了所有灰色对象对白色对象的直接或者间接引用<br>这种问题很大, 因为本来程序运行所需要的一个对象被销毁了, 会导致程序的异常, 那么垃圾回收器给出了我们两种如下解决方案.</li>
</ul>
<h3 id="5-2-4-解决方案"><a href="#5-2-4-解决方案" class="headerlink" title="5.2.4 解决方案"></a>5.2.4 解决方案</h3><ul>
<li>增量更新(Increment update)<br>破坏的是第一个条件, 他会将这个新插入的引用记录下来, 扫描结束之后会以黑色对象为根重新进行扫描,可以理解为这个技术可以使得产生的新引用的黑色节点变灰.其主要实现为写屏障; 主要用于CMS中</li>
<li>原始快照(SnapShot At The Beginning)<br>破坏的主要是第二个条件, 他会在断开连接时将断开连接前的一瞬间记录下来, 再将他放到一个独立的内存区域中, 扫描结束后, 重新以灰色节点为根重新进行扫描.</li>
</ul>
<h2 id="5-3-G1垃圾回收器的垃圾处理流程"><a href="#5-3-G1垃圾回收器的垃圾处理流程" class="headerlink" title="5.3 G1垃圾回收器的垃圾处理流程"></a>5.3 G1垃圾回收器的垃圾处理流程</h2><h3 id="5-3-1-以rigion为分区的回收范围改变"><a href="#5-3-1-以rigion为分区的回收范围改变" class="headerlink" title="5.3.1 以rigion为分区的回收范围改变"></a>5.3.1 以rigion为分区的回收范围改变</h3><p>首先我们需要知道，G1相较于CMS包括之前的垃圾回收器做出了一个巨大的改变，就是垃圾回收区域的划分，以前分代收集理论是垃圾回收器的主流理论，而G1将其做了一个更新包装，其面向堆内任何部分来组成回收集(Cset)，每一个回收集被叫做region区域，每一个区域中也可扮演为Eden，Survivor空间，每次回收的最小单元是一个region，而对于不同的region区域采取不同的策略，对于垃圾回收产生了更为优秀的结果。G1收集器会自动的去评估每个region区域的回收价值大小，根据<code>-XX:MaxGCPauseMillis</code>参数来确定回收策略，我们叫这种模式为<code>Mixed GC</code>。相比于之前，有两个优点，一个是变得更加灵活了，有回收策略了；另一个是不再需要连续了，内存空间的分配也会更加合理。<br>那么在我们了解了这种化整为零的内存空间分配策略后，我们需要知道整个G1回收器的垃圾回收流程：<br><img src="/images/G1.png"></p>
<h3 id="5-3-2-Young-GC"><a href="#5-3-2-Young-GC" class="headerlink" title="5.3.2 Young GC"></a>5.3.2 Young GC</h3><p>程序在运行的时候，随着对象不断创建，许多内存进行Eden区，当Eden区被占满时，会自动触发一次<code>Young GC</code>，此时会引起STW，此时G1涉及的对象只有Eden区和Survivor区,回收的内存进入<code>Cset</code>中进行回收;运用了复制算法,将存活单位复制到新的survivor区域.</p>
<ul>
<li>扫描根和rset, 此时会有一个小的短暂的STW;</li>
<li>运用写屏障更新rset,此时所有跨代引用对象不会被视为垃圾;</li>
<li>复制算法,实现Eden区和Survivor区的存活对象到新的Survivor区的转移</li>
<li>处理软弱虚引用.</li>
</ul>
<h3 id="5-3-3-Young-GC-Concurrent-Marking"><a href="#5-3-3-Young-GC-Concurrent-Marking" class="headerlink" title="5.3.3 Young GC + Concurrent Marking"></a>5.3.3 Young GC + Concurrent Marking</h3><ul>
<li>首先进行一次young GC, 同时进行一次进行一次初始标记, 标记GC Root对象, 此时会发生STW;</li>
<li>并发标记, 沿着GC Root遍历对象, 同时将所有跨代引用的标记变脏,此时属于并发标记, 不会STW; 同时也会进行SATB, 对漏标的对象进行了处理;</li>
<li>再次标记, 处理原来SATB的对象; </li>
<li>独占清理, 对每一块内存区域进行排序, 为下阶段Mixed GC做准备;</li>
<li>清理本阶段内存.</li>
</ul>
<h3 id="5-3-4-Mixed-GC"><a href="#5-3-4-Mixed-GC" class="headerlink" title="5.3.4 Mixed GC"></a>5.3.4 Mixed GC</h3><p>此时会根据<code>-XX:MaxGCPauseMillis</code>实现清理策略, 在这个阶段会做三件事:</p>
<ul>
<li>新生代的垃圾回收: Eden区存活对象到survivor区; Survivor区存活对象到新的survivor区; </li>
<li>晋升: Survivor区达到晋升阈值的对象晋升到老年代</li>
<li>老年代的垃圾回收: 结合<code>-XX:MaxGCPauseMillis</code>和上一阶段的排序, 将部分老年代进行回收;<br>这个阶段也说明了Garbage First这个垃圾回收器名字的由来, 就是会在这个环节优先回收占用内存较多的区域.<blockquote>
<p><code>-XX:MaxGCPauseMillis</code>: 最大暂停时间过短, 回收速度小于产生速度, 触发单线程的Full GC; 正常情况, 回收速度大于产生速度, Concurrent mark;<br><code>-XX：G1MixedGCLiveThresholdPercent</code>: 回收阈值,默认为65%; 达到之后才会触发回收, 过小意味着存活对象多,复制时间浪费多, STW时间长．</p>
</blockquote>
</li>
</ul>
<h2 id="5-4-新增功能"><a href="#5-4-新增功能" class="headerlink" title="5.4 新增功能"></a>5.4 新增功能</h2><h3 id="5-4-1-字符串去重"><a href="#5-4-1-字符串去重" class="headerlink" title="5.4.1 字符串去重"></a>5.4.1 字符串去重</h3><ul>
<li>优点：节省大量内存</li>
<li>缺点：略微多占用了 cpu 时间，新生代回收时间略微增加<br><code>-XX:+UseStringDeduplication</code><br>将所有新分配的字符串放入一个队列; 当新生代回收时，G1并发检查是否有字符串重复; 如果它们值一样，让它们引用同一个 char[]<blockquote>
<p>注意: 与 String.intern() 不一样; String.intern() 关注的是字符串对象; 而字符串去重关注的是 char[]; 在 JVM 内部，使用了不同的字符串表</p>
</blockquote>
</li>
</ul>
<h3 id="5-4-2-类卸载"><a href="#5-4-2-类卸载" class="headerlink" title="5.4.2 类卸载"></a>5.4.2 类卸载</h3><p>所有对象都经过并发标记后，就能知道哪些类不再被使用，当一个类加载器的所有类都不再使用，则卸载它所加载的所有类<br>-XX:+ClassUnloadingWithConcurrentMark 默认启用</p>
<h3 id="5-4-3-巨型对象管理"><a href="#5-4-3-巨型对象管理" class="headerlink" title="5.4.3 巨型对象管理"></a>5.4.3 巨型对象管理</h3><p>一个对象大于 region 的一半时，称之为巨型对象<br>G1 不会对巨型对象进行拷贝<br>回收时被优先考虑<br>G1 会跟踪老年代所有 incoming 引用，这样老年代 incoming 引用为0 的巨型对象就可以在新生代垃圾回收时处理掉</p>
<h1 id="6-ZGC收集器"><a href="#6-ZGC收集器" class="headerlink" title="6. ZGC收集器"></a>6. ZGC收集器</h1><p>是一款低延迟垃圾收集器, 希望在对吞吐量影响不大的前提下, 把垃圾收集的停顿时间缩短在10ms以内。<br>其内存布局也是和G1一样划分为若干Region区，但其具有动态的容量大小和动态创建和销毁的特征，可以分为如下三种容量：</p>
<ul>
<li>大： 不固定可以动态变换，但是一定为2MB的整数倍，不会被重分配。</li>
<li>中： 容量固定为32MB， 用来存储256KB ~ 4MB的对象</li>
<li>小： 容量固定为2MB， 用来存储0 ~ 256KB的对象</li>
</ul>
<h2 id="6-1-ZGC的垃圾收集流程"><a href="#6-1-ZGC的垃圾收集流程" class="headerlink" title="6.1 ZGC的垃圾收集流程"></a>6.1 ZGC的垃圾收集流程</h2><h3 id="6-1-1-并发标记-Concurrent-Marking"><a href="#6-1-1-并发标记-Concurrent-Marking" class="headerlink" title="6.1.1 并发标记(Concurrent Marking)"></a>6.1.1 并发标记(Concurrent Marking)</h3><p>只会在开始标记GC Root的时候有小小的停顿，剩下的标记活动都是并发运行的。和G1需要STW进行三色算法不同，ZGC的标记位置是在指针上的，所以可以省略去遍历对象图的流程</p>
<h3 id="6-1-2-并发预备重分配-Concurrent-Perpare-for-Relocation"><a href="#6-1-2-并发预备重分配-Concurrent-Perpare-for-Relocation" class="headerlink" title="6.1.2 并发预备重分配(Concurrent Perpare for Relocation)"></a>6.1.2 并发预备重分配(Concurrent Perpare for Relocation)</h3><p>通过并发标记得出的结论查询到底有哪些垃圾是需要回收的，然后将需要回收的Region区组成重分配集(Relocation Set)。因为ZGC不区分新生代老年代的特点，所以该阶段的扫描是针对全堆的，但同时相较于G1也省去了记忆集的维护成本。</p>
<blockquote>
<p>ZGC的重分配集只是决定了里面的存活对象会被重新复制到其他的Region中，而不是说回收的行为针对这个集合里面的region进行。</p>
</blockquote>
<h3 id="6-1-3-并发重分配-Concurrent-Relocation"><a href="#6-1-3-并发重分配-Concurrent-Relocation" class="headerlink" title="6.1.3 并发重分配(Concurrent Relocation)"></a>6.1.3 并发重分配(Concurrent Relocation)</h3><p>是ZGC垃圾回收的核心过程。他将重分配集中的存活对象转移到新的Region中，并在重分配集中建立一个转发表(Forward Table)，用来标记重分配区中旧的Region对象到新的Region对象的转发关系。当用户访问了重分配集中的对象，那么就会被预置的内存屏障所截获，根据转发表的记录转发到新的对象上，并将引用更改到新的对象上，使其指向新的对象。这种行为被称为指针的“自愈”行为。<br>一旦region的存活对象都被复制完毕，那么这个region就可以进行下一轮的内存分配。但是转发表却得等到所有重分配集中的region对象复制完毕才可删除。</p>
<h3 id="6-1-4-并发重映射-Concurrent-Remap"><a href="#6-1-4-并发重映射-Concurrent-Remap" class="headerlink" title="6.1.4 并发重映射(Concurrent Remap)"></a>6.1.4 并发重映射(Concurrent Remap)</h3><p>重映射指的是修正整个堆中指向重分配集中的旧对象的所有引用。，可以合并到下一次的并发标记的流程进行，节约一次遍历对象图的操作。</p>
<h2 id="6-2-ZGC解决并发算法问题的关键——染色指针"><a href="#6-2-ZGC解决并发算法问题的关键——染色指针" class="headerlink" title="6.2 ZGC解决并发算法问题的关键——染色指针"></a>6.2 ZGC解决并发算法问题的关键——染色指针</h2><p>将少量标识信息存储在指针上，实现可达性分析，相较于G1的遍历对象图节约了许多时间的成本。<br>三个优点：</p>
<ol>
<li>染色指针可以使得一旦某个Region的存活对象被移走之后，这个Region立即就能被释放和重用。指针的自愈行为使得它拥有即时性，而复制算法则是需要STW进行1：1的复制后才能够实现重用。</li>
<li>染色指针可以大幅度减少在垃圾收集过程中内存屏障的使用数量，内存屏障的功能之一就是记录对象引用的变动情况，而染色指针可以接替这一工作。</li>
<li>可以作为一种可拓展的存储结构用来记录，重定位过程的相关数据，日后可以进一步提升性能。日后标志位可用的提升可以使得其更有扩展性。</li>
</ol>

      
    </div>

    
    
    
      <footer class="post-footer">
        <div class="post-eof"></div>
      </footer>
  </article>
  
  
  

      
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://daorongxing.gitee.io/post/18463/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="Daorong Xing">
      <meta itemprop="description" content="这是我的个人博客，记录计算机学习之路！">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="邢道荣的个人博客">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          
            <a href="/post/18463/" class="post-title-link" itemprop="url">C++指针和结构体的浅显认知</a>
        </h2>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>
              

              <time title="创建时间：2022-11-25 11:50:30 / 修改时间：16:52:41" itemprop="dateCreated datePublished" datetime="2022-11-25T11:50:30+08:00">2022-11-25</time>
            </span>
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-folder"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/C/" itemprop="url" rel="index"><span itemprop="name">C++</span></a>
                </span>
            </span>

          <br>
            <span class="post-meta-item" title="本文字数">
              <span class="post-meta-item-icon">
                <i class="far fa-file-word"></i>
              </span>
                <span class="post-meta-item-text">本文字数：</span>
              <span>2k</span>
            </span>
            <span class="post-meta-item" title="阅读时长">
              <span class="post-meta-item-icon">
                <i class="far fa-clock"></i>
              </span>
                <span class="post-meta-item-text">阅读时长 &asymp;</span>
              <span>2 分钟</span>
            </span>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
          <p>因为数据结构中会设计到C++的一些基本指针操作，在进行算法的时候或多或少链表，哈希表，二叉树也会涉及一些相应的指针操作，而本人对于C++这么博大精深的语言体系又只有浅浅的一些了解，所以将这些数据结构涉及到的底层的指针做一个简单的知识梳理，方便以后在理解算法的时候尽量少花点笔墨放在基础语法知识上。</p>
<hr>
<h1 id="1-指针"><a href="#1-指针" class="headerlink" title="1. 指针"></a>1. 指针</h1><h2 id="1-1-指针的意义"><a href="#1-1-指针的意义" class="headerlink" title="1.1 指针的意义"></a>1.1 指针的意义</h2><p>对于C++程序的一个数据，我们一般需要做到关注他如下的三个部分：</p>
<ul>
<li><code>data</code> : 数据的内容</li>
<li><code>address</code> : 数据的地址（存储位置）</li>
<li><code>dtype</code> : 数据的类型</li>
</ul>
<p>那么平时我们在定义一个变量的时候，一般只会定义他的数据类型和数据的内容(<code>int a = 5</code>)，那么他的地址又指的是什么呢？</p>
<p>我们可以这样去理解：<mark>代码中出现的变量存放在主机里存储器中的一个个存储单元中，每一个存储单元都有一个地址。</mark>换而言之，我们作为程序员更多的会去关注字面值的内容，而地址更像是计算机底层程序自己考虑的。当我们定义完一个变量要去调用他的时候，我们需要进行的操作仅仅是运用运算符<code>=</code>, 而计算机底层则需要对应的去寻找这个变量的地址，再将其调用出来。指针像是一种<strong>工具</strong>，模拟了这种过程，我们可以通过指针<u><strong>直接知道其指向的地址</strong></u>，也可以<u><strong>获取他指向的值</strong></u>。</p>
<p>用听起来厉害一点的话来讲就是：**<font color=red>指针可以精准控制了内存中的地址，从而高效率的传递和更改数据。</font>**</p>
<h2 id="1-2-指针和引用"><a href="#1-2-指针和引用" class="headerlink" title="1.2 指针和引用"></a>1.2 指针和引用</h2><ul>
<li><p>&amp; ： 取地址运算符<br>针对于变量，<code>&amp; + 变量名称</code>表示的是该变量在内存中的地址。</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> a = <span class="number">10</span>;</span><br><span class="line">cout&lt;&lt; &amp;a &lt;&lt; endl;</span><br></pre></td></tr></table></figure>
<p>输出的结果是：<code>004FFDE0</code></p>
</li>
<li><p>*： 间接运算符</p>
</li>
</ul>
<p>针对的是指针，<code>* + 指针名称</code>表示引用该指针指向的值。<br><code>*p</code>表示取p指针指向地址的值<br><code>int* p</code>表示p的数据类型是<mark>指向int类型的指针</mark></p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> a = <span class="number">10</span>;</span><br><span class="line">cout&lt;&lt; &amp;a &lt;&lt; endl;</span><br><span class="line"><span class="type">int</span>* p = &amp;a; <span class="comment">//表示p是指向int类型的a变量的地址的指针</span></span><br><span class="line">cout&lt;&lt; *p &lt;&lt;endl;</span><br></pre></td></tr></table></figure>
<p>输出的结果是：<code>004FFDE0</code>; <code>10</code></p>
<p><font size=2>某种意义上，int*  p &#x3D;int * p ; 但是他们表示的含义完全不同。左值定义了一个指针，右值定义了一个变量。但是他们最终的结果是相等的。但是要注意的是，在程序编译器中，int* p1, p2指的是定义一个p1为指向int类型的指针，p2为int类型的变量。</font></p>
<hr>
<h1 id="2-结构体"><a href="#2-结构体" class="headerlink" title="2. 结构体"></a>2. 结构体</h1><h2 id="2-1-结构体的定义"><a href="#2-1-结构体的定义" class="headerlink" title="2.1 结构体的定义"></a>2.1 结构体的定义</h2><p>类似于类，可以表示一个需要用各种数据类型表示的数据集体，如学生有他的姓名年龄，那么此时就需要进行结构体的定义，将学生封装为<code>char</code>类型的姓名和包括<code>int</code>类型的年龄。<br><br>具体在C++中表达如下：</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">struct</span> <span class="title class_">Student</span> &#123;</span><br><span class="line">  <span class="type">char</span>[<span class="number">20</span>] name;</span><br><span class="line">  <span class="type">int</span> age;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>他在数据结构中用处十分之大，比如链表中需要定义<code>data</code>和<code>next</code>，又比如在二叉树中需要定义双亲和头节点等。都需要用到结构体。</p>
<h2 id="2-2-结构体的初始化"><a href="#2-2-结构体的初始化" class="headerlink" title="2.2 结构体的初始化"></a>2.2 结构体的初始化</h2><p>结构体的初始化有如下两种方式：</p>
<ul>
<li>通过直接定义初始化<br><code>struct Student s1;</code>：表示构造出一个数据类型为<code>Student</code>的学生变量<code>s1</code>。<br>注意：此类型构造需要确定结构体定义的位置，如果在同一个方法内可以调用，在不同方法内不能调用。如果结构体被设置为全局则每个方法都可以引用。</li>
<li>在构造时完成初始化<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">struct</span> <span class="title class_">Student</span> &#123;</span><br><span class="line">  <span class="type">char</span>[<span class="number">20</span>] name;</span><br><span class="line">  <span class="type">int</span> age;</span><br><span class="line">&#125;,s1,s2</span><br></pre></td></tr></table></figure>
这样就表示<code>s1,s2</code>两个变量是<code>Student</code>类型，并且再后续无需再定义就可以直接使用，在构造的时候就完成了初始化。</li>
</ul>
<h2 id="2-3-typedef关键字"><a href="#2-3-typedef关键字" class="headerlink" title="2.3 typedef关键字"></a>2.3 typedef关键字</h2><p><code>typedef</code>关键字可以简化结构体变量的初始化，通过该关键字可以给结构体起别名，从而直接实现通过别名来进行调用。</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">typedef</span> <span class="keyword">struct</span> <span class="title class_">Student</span> &#123;</span><br><span class="line">  <span class="type">char</span>[<span class="number">20</span>] name;</span><br><span class="line">  <span class="type">int</span> age;</span><br><span class="line">&#125;,S,s1</span><br></pre></td></tr></table></figure>
<blockquote>
<p>其中，S为结构体的别名，s1为结构体类型的变量。</p>
</blockquote>
<h2 id="2-4-结构体成员变量的调用"><a href="#2-4-结构体成员变量的调用" class="headerlink" title="2.4 结构体成员变量的调用"></a>2.4 结构体成员变量的调用</h2><p>通过<code>.</code>的形式调用。<br>如<code>s1.age</code>表示第一名学生的年龄；<code>s2.name</code>表示第二名学生的姓名。</p>
<hr>
<h1 id="3-指向结构体的指针"><a href="#3-指向结构体的指针" class="headerlink" title="3. 指向结构体的指针"></a>3. 指向结构体的指针</h1><p>此时结构体可以视为数据类型，所以指针定义写法和原先指针写法差别不大。<br><code>struct Student* p= &amp;s1</code></p>
<blockquote>
<p>指向结构体Student的指针p(左值)，指向(&#x3D;)数据类型为Student的s1的地址(右值)。</p>
</blockquote>
<ul>
<li><font size=4 color=red><b>指针访问结构体成员变量</b></font><br>用箭头函数：<br><code>p-&gt;name</code><blockquote>
<p>无需带变量名，因为p指向了地址，知道需要获取哪个变量的值</p>
</blockquote>
</li>
</ul>
<hr>
<p>本篇只针对于目前个人认为可能会在数据结构中用到的知识点，对于真正的指针和结构体的知识知识九牛一毛不尽完整，而对于有关于理解数据结构语法有帮助的知识点，如有遗漏或者后续想到的，接下来再来进行补充。</p>

      
    </div>

    
    
    
      <footer class="post-footer">
        <div class="post-eof"></div>
      </footer>
  </article>
  
  
  

      
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://daorongxing.gitee.io/post/11079/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="Daorong Xing">
      <meta itemprop="description" content="这是我的个人博客，记录计算机学习之路！">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="邢道荣的个人博客">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          
            <a href="/post/11079/" class="post-title-link" itemprop="url">2.LinkList</a>
        </h2>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>

              <time title="创建时间：2022-11-24 19:57:49" itemprop="dateCreated datePublished" datetime="2022-11-24T19:57:49+08:00">2022-11-24</time>
            </span>
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="far fa-calendar-check"></i>
                </span>
                <span class="post-meta-item-text">更新于</span>
                <time title="修改时间：2022-11-28 22:05:35" itemprop="dateModified" datetime="2022-11-28T22:05:35+08:00">2022-11-28</time>
              </span>
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-folder"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/%E7%AE%97%E6%B3%95/" itemprop="url" rel="index"><span itemprop="name">算法</span></a>
                </span>
            </span>

          <br>
            <span class="post-meta-item" title="本文字数">
              <span class="post-meta-item-icon">
                <i class="far fa-file-word"></i>
              </span>
                <span class="post-meta-item-text">本文字数：</span>
              <span>8.3k</span>
            </span>
            <span class="post-meta-item" title="阅读时长">
              <span class="post-meta-item-icon">
                <i class="far fa-clock"></i>
              </span>
                <span class="post-meta-item-text">阅读时长 &asymp;</span>
              <span>8 分钟</span>
            </span>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
          <h1 id="1-链表的基础定义"><a href="#1-链表的基础定义" class="headerlink" title="1. 链表的基础定义"></a>1. 链表的基础定义</h1><h2 id="1-1-主要组成"><a href="#1-1-主要组成" class="headerlink" title="1.1 主要组成"></a>1.1 主要组成</h2><ul>
<li><code>data</code>域： 用于存储每一个节点的<strong>数据</strong></li>
<li><code>next</code>域： 用于存储指向下一个节点的<strong>指针</strong></li>
</ul>
<h2 id="1-2-特点"><a href="#1-2-特点" class="headerlink" title="1.2 特点"></a>1.2 特点</h2><ul>
<li>最后指向null，意味着链表的结束。</li>
<li>可以无限扩容，通过指针指向其他元素可以实现空间的扩大。</li>
<li><mark>存储结构特点</mark>：链表是通过指针域的指针链接在内存中各个节点。所以链表中的节点在内存中不是连续分布的 ，而是散乱分布在内存中的某地址上，分配机制取决于操作系统的内存管理。</li>
<li>相较于数组而言，插入，删除方便，查找不方便（需要一个一个去找）</li>
</ul>
<h2 id="1-3-图表写法"><a href="#1-3-图表写法" class="headerlink" title="1.3 图表写法"></a>1.3 图表写法</h2><p><img src="/images/LinkListStructure.png"></p>
<h2 id="1-4-相关类型"><a href="#1-4-相关类型" class="headerlink" title="1.4 相关类型"></a>1.4 相关类型</h2><p>近似的我们可以分为如下几种类型：</p>
<ul>
<li><font size=4><b>单链表</b></font><br>如上图，是一般的数据模型形式。<br><br></li>
<li><font size=4><b>双链表</b></font><br>在单链表的基础上增加了一个<code>next</code>域，即一个节点有两个<code>next</code>域，一个指向前面的节点，一个指向后面的节点。这样能够一定程度上提高查找的效率。<br><img src="/images/doubleLinkList.png"><br></li>
<li><font size=4><b>循环链表</b></font><br>即最后的<code>next</code>指向的是<code>head</code>，实现了链表的循环。可以解决约瑟夫环问题。<br><img src="/images/circleLinkList.png"></li>
</ul>
<h2 id="1-5-数据结构相关操作"><a href="#1-5-数据结构相关操作" class="headerlink" title="1.5 数据结构相关操作"></a>1.5 数据结构相关操作</h2><p>下面是链表有关的数据结构操作：</p>
<ul>
<li><font size=4><b>初始化链表结构</b></font><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">Struct LinkNode&#123;</span><br><span class="line">    <span class="type">int</span> data;  <span class="comment">// 定义data域内容</span></span><br><span class="line">    ListNode *next; <span class="comment">//指向ListNode类型元素的指针</span></span><br><span class="line">    <span class="comment">// 构造函数的初始化</span></span><br><span class="line">    <span class="built_in">ListNode</span>(<span class="type">int</span> x)&#123;</span><br><span class="line">        <span class="built_in">data</span>(x);</span><br><span class="line">        <span class="built_in">next</span>(null)&#123;&#125;;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<br></li>
<li><font size=4><b>初始化节点</b></font><br><code>ListNode* head = new ListNode(5);</code><br><br><br></li>
<li><font size=4><b>删除节点</b></font></li>
</ul>
<p>链表节点删除的主要思想有两个，第一个是<strong>寻找到要删除的位置</strong>，这个很简单实现，比对要删除的元素和指针指向的元素是否相等，如果不相等就<code>p = p-&gt;next</code>，移动到下个节点即可，难点是理解确定寻址指针指向的位置和删除元素的位置关系。而<mark>寻址指针指向的位置是删除元素的前一格</mark>，这个和后面具体删除的思想有关。</p>
<p>第二个是<strong>删除的过程操作</strong>，其中细化出来有两步，第一步是指向要删除的节点，之后直接<code>delete</code>带走即可，第二步是将原来指向删除节点的<code>next</code>域指针指向删除节点的下一个。综合这两个我们可以发现在删除节点前一个节点要做的事情是可以和其他联系起来的，他的<code>next</code>指向的就是删除的，而他的<code>next</code>我们后续也要进行操作。所以这就回应了第一个寻址思想的难点。<br><br><br><img src="/images/LinkListDel.png"><br><strong>实现代码如下：</strong></p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">void</span> <span class="title">DeleteElem</span><span class="params">(link L,<span class="type">int</span> i)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">link p=L,q;</span><br><span class="line"><span class="type">int</span> j=<span class="number">0</span>;</span><br><span class="line"><span class="keyword">while</span>(p &amp;&amp; j&lt;i<span class="number">-1</span>)</span><br><span class="line">&#123;</span><br><span class="line">p = p-&gt;next;</span><br><span class="line">j++;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">if</span>(!p||!p-&gt;next)</span><br><span class="line">&#123;cout&lt;&lt;<span class="string">&quot;输出位置不合法&quot;</span>&lt;&lt;<span class="string">&quot; &quot;</span>;</span><br><span class="line"><span class="built_in">exit</span>(<span class="number">1</span>);</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">else</span>&#123;</span><br><span class="line">q = p-&gt;next;</span><br><span class="line">p-&gt;next = q-&gt;next;</span><br><span class="line"><span class="keyword">delete</span> q;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<br>
- <font size=4><b>增加节点</b></font>

<p>很简单也是两步操作，<strong>第一步是定位</strong>，定位和操作和删除的差不多；<strong>第二步是增加</strong>，那么应该怎么增加呢？我们需要新引入一个指针来进行节点赋值和节点位置的操作，<u>节点赋值</u>很简单，就是<code>s-&gt;data = elem</code>，<u>节点的位置</u>也不难，因为插入元素，即要插入位置的原来节点得给你让出来，你要干他的事情，你的<code>next</code>就要指向原来节点的<code>next</code>即，<code>s-&gt;next = p-&gt;next</code>，那么你要成为他的一部分得连起来，那么原来的<code>next</code>就要指向你的元素，即<code>p-&gt;next = s</code>。<mark>注意这两步的顺序不可以搞反</mark>。<br><br><br><img src="/images/addElem.png"><br><br><br>代码如下：</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">void</span> <span class="title">AddElem</span><span class="params">(link &amp;L, <span class="type">int</span> i, <span class="type">int</span> e)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    link p = L, s;</span><br><span class="line"> <span class="type">int</span> j=<span class="number">0</span>;</span><br><span class="line"> <span class="keyword">while</span>(p &amp;&amp; j&lt;i<span class="number">-1</span>)</span><br><span class="line"> &#123;</span><br><span class="line"> p = p-&gt;next;</span><br><span class="line"> j++;</span><br><span class="line"> &#125; <span class="comment">//搜索插入的位置</span></span><br><span class="line"> <span class="keyword">if</span>(!p)</span><br><span class="line">	 &#123;cout&lt;&lt;<span class="string">&quot;增加位置不合法&quot;</span>&lt;&lt;endl;</span><br><span class="line"> <span class="built_in">exit</span>(<span class="number">1</span>);</span><br><span class="line"> &#125;</span><br><span class="line"> <span class="keyword">else</span>&#123;</span><br><span class="line"> s = <span class="keyword">new</span> Node; <span class="comment">//为新节点创建位置</span></span><br><span class="line"> s-&gt;Data = e; <span class="comment">//赋值</span></span><br><span class="line"> s-&gt;next = p-&gt;next;</span><br><span class="line"> p-&gt;next = s;</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<ul>
<li><font size=4><b>寻找data所对应的节点</b></font><br>删除增加的基础，不再赘述。</li>
</ul>
<hr>
<h1 id="2-链表设计"><a href="#2-链表设计" class="headerlink" title="2. 链表设计"></a>2. 链表设计</h1><h2 id="相关题目"><a href="#相关题目" class="headerlink" title="相关题目"></a>相关题目</h2><p><img src="https://leetcode.cn/problems/remove-linked-list-elements/" alt="Problem 203. 移除链表元素"><br><img src="https://leetcode.cn/problems/design-linked-list/" alt="Problem 707. 设计链表"></p>
<blockquote>
<p>很好的数据结构方式，也是数据结构这门课中第一次学到的关于指针类型的数据结构，有一定的难度，又是我们的启蒙，是一门十分值得敬畏的章节。加油吧。不管前路怎么艰辛，这总是你的第一站，第一站总是会变的比较有难度一些的，那么你就一定要坚持下去，同时照顾好自己的身体，资本要有，但挥霍资本的资本也要有。</p>
</blockquote>
<h2 id="2-1-复杂度"><a href="#2-1-复杂度" class="headerlink" title="2.1 复杂度"></a>2.1 复杂度</h2><p>大部分是<code>O(n)</code></p>
<h2 id="2-2-主要思想"><a href="#2-2-主要思想" class="headerlink" title="2.2 主要思想"></a>2.2 主要思想</h2><p>这里学到了一个比较重要的东西叫做虚拟头节点，他存在的意义是为了让处理头结点的时候和处理其他节点一样的自然。因为链表这种数据结构本身具有一定的局限性，其头节点无法用next指向，所以设置一个虚拟头节点，可以让头节点获得和其他节点一样的待遇。</p>
<h2 id="2-3-注意点"><a href="#2-3-注意点" class="headerlink" title="2.3 注意点"></a>2.3 注意点</h2><ul>
<li>注意什么时候需要定位到要操作节点的前一个节点，什么时候要确定的定位到那个要操作的节点。要操作节点的前一个节点主要用于添加和删除这两个操作，因为他们都需要用到前一个节点的next指针，来指向下一个节点方能对他们进行操作。而确定的定位到要操作的节点则是根据index取值的操作。</li>
<li>需要警惕提防节点们，因为节点们在你每次更改next域之后，他们之间的关系就进行了一次大洗牌，所以在新增和删除节点的时候一定要按步骤操作好。</li>
<li>有索引就有越界问题，一定看看要搜索定位的索引是否越界或者不存在。</li>
<li>用好<code>while(index--)</code>的写法，他其实和<code>for(int i = 0; i++; i &lt; index)</code>是一样的，但是他的优点就是能加上一些<code>&amp;&amp;</code>，从而可以做出一些防止越界的举动。</li>
<li>记得在操作的时候时刻不要拿着最原始的head变量去操作，因为要返回head的时候能够帮你直接定位，而用一些替代值去进行操作就好了。</li>
</ul>
<h2 id="2-4-代码实现"><a href="#2-4-代码实现" class="headerlink" title="2.4 代码实现"></a>2.4 代码实现</h2><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">MyLinkedList</span> &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line"><span class="keyword">struct</span> <span class="title class_">LinkNode</span>&#123;</span><br><span class="line">    <span class="type">int</span> val;</span><br><span class="line">    LinkNode* next;</span><br><span class="line">    <span class="built_in">LinkNode</span>(<span class="type">int</span> val): <span class="built_in">val</span>(val), <span class="built_in">next</span>(<span class="literal">nullptr</span>)&#123;&#125;</span><br><span class="line">&#125;;</span><br><span class="line">    <span class="built_in">MyLinkedList</span>() &#123;</span><br><span class="line">        size = <span class="number">0</span>; <span class="comment">//长度</span></span><br><span class="line">        dummyHead = <span class="keyword">new</span> <span class="built_in">LinkNode</span>(<span class="number">0</span>); <span class="comment">//虚拟头节点</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="type">int</span> <span class="title">get</span><span class="params">(<span class="type">int</span> index)</span> </span>&#123;</span><br><span class="line">        <span class="comment">//有下标需要考虑越界问题</span></span><br><span class="line">        <span class="keyword">if</span>(index &gt; size - <span class="number">1</span> || index &lt; <span class="number">0</span>)&#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        LinkNode* cur = dummyHead -&gt; next;</span><br><span class="line">        <span class="keyword">while</span>(index --) &#123;</span><br><span class="line">            cur = cur -&gt; next;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> cur -&gt; val;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">addAtHead</span><span class="params">(<span class="type">int</span> val)</span> </span>&#123;</span><br><span class="line">        LinkNode* cur = <span class="keyword">new</span> <span class="built_in">LinkNode</span>(val);</span><br><span class="line">        cur -&gt; next = dummyHead -&gt; next;</span><br><span class="line">        dummyHead -&gt; next = cur;</span><br><span class="line">        size++;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">addAtTail</span><span class="params">(<span class="type">int</span> val)</span> </span>&#123;</span><br><span class="line">        LinkNode* cur = <span class="keyword">new</span> <span class="built_in">LinkNode</span>(val);</span><br><span class="line">        LinkNode* p = dummyHead;</span><br><span class="line">        <span class="comment">//把尾节点给找出来</span></span><br><span class="line">        <span class="keyword">while</span>(p -&gt; next != <span class="literal">nullptr</span>)&#123;</span><br><span class="line">            p = p -&gt; next;</span><br><span class="line">        &#125;</span><br><span class="line">        p -&gt; next = cur;</span><br><span class="line">        size++;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">addAtIndex</span><span class="params">(<span class="type">int</span> index, <span class="type">int</span> val)</span> </span>&#123;</span><br><span class="line">        <span class="comment">// 小于零则在头部插入节点</span></span><br><span class="line">        <span class="keyword">if</span>(index &lt; <span class="number">0</span>)&#123;</span><br><span class="line">            index = <span class="number">0</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 越界则无效</span></span><br><span class="line">        <span class="keyword">if</span>(index &gt; size)&#123;</span><br><span class="line">            <span class="keyword">return</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        LinkNode* p = dummyHead;</span><br><span class="line">        LinkNode* cur = <span class="keyword">new</span> <span class="built_in">LinkNode</span>(val);</span><br><span class="line">        <span class="keyword">while</span>(index--)&#123;</span><br><span class="line">            p = p -&gt; next;</span><br><span class="line">        &#125;</span><br><span class="line">        cur -&gt; next = p -&gt; next;</span><br><span class="line">        p -&gt; next = cur;</span><br><span class="line">        size++;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">deleteAtIndex</span><span class="params">(<span class="type">int</span> index)</span> </span>&#123;</span><br><span class="line">		<span class="comment">//判断索引是否越界</span></span><br><span class="line">        <span class="keyword">if</span>(index &gt; size - <span class="number">1</span> || index &lt; <span class="number">0</span>)&#123;</span><br><span class="line">            <span class="keyword">return</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        LinkNode* cur = dummyHead;</span><br><span class="line">        <span class="keyword">while</span>(index--) &#123;</span><br><span class="line">            cur = cur -&gt; next;</span><br><span class="line">        &#125;</span><br><span class="line">        LinkNode* p = cur -&gt; next;</span><br><span class="line">        cur -&gt; next = p -&gt; next;</span><br><span class="line">        <span class="keyword">delete</span> p;</span><br><span class="line">        size--;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">	<span class="function">ListNode* <span class="title">removeElements</span><span class="params">(ListNode* head, <span class="type">int</span> val)</span> </span>&#123;</span><br><span class="line">		<span class="comment">//虚拟头节点的建立</span></span><br><span class="line">        ListNode* dummyHead = <span class="keyword">new</span> <span class="built_in">ListNode</span>();</span><br><span class="line">        dummyHead-&gt;next = head;</span><br><span class="line">        ListNode* cur = dummyHead;</span><br><span class="line">		<span class="keyword">while</span>(cur-&gt;next != <span class="literal">NULL</span>)&#123;</span><br><span class="line">    		<span class="keyword">if</span>(cur-&gt;next-&gt;val == val)&#123;</span><br><span class="line">    			ListNode* tmp = cur-&gt;next;</span><br><span class="line">        		cur-&gt;next = cur -&gt;next-&gt;next;</span><br><span class="line">        		<span class="keyword">delete</span> tmp;</span><br><span class="line">    &#125;</span><br><span class="line">    		<span class="keyword">else</span>&#123;</span><br><span class="line">        		cur = cur -&gt; next;	</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line">		head = dummyHead-&gt;next;</span><br><span class="line">		<span class="keyword">delete</span> dummyHead;</span><br><span class="line">		<span class="keyword">return</span> head;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span>:</span><br><span class="line">        LinkNode* dummyHead;</span><br><span class="line">        <span class="type">int</span> size;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

<h1 id="3-链表翻转"><a href="#3-链表翻转" class="headerlink" title="3. 链表翻转"></a>3. 链表翻转</h1><h2 id="相关题目-1"><a href="#相关题目-1" class="headerlink" title="相关题目"></a>相关题目</h2><p><img src="https://leetcode.cn/problems/reverse-linked-list/" alt="Problem 206 链表翻转"></p>
<h2 id="3-2-复杂度"><a href="#3-2-复杂度" class="headerlink" title="3.2 复杂度"></a>3.2 复杂度</h2><p>时间复杂度：<code>O(n)</code><br>空间复杂度：<code>O(1)</code></p>
<h2 id="3-3-主要思想"><a href="#3-3-主要思想" class="headerlink" title="3.3 主要思想"></a>3.3 主要思想</h2><p>只要实现链表的转向即可，那么就需要有一前一后两个节点，来实现转向的操作，于是链表的转向就可以实现了。 其实这里又是双指针的另一个应用场景，双指针只要涉及到需要对两个东西同时进行操作，他都能够派上用场。</p>
<h2 id="3-4-注意点"><a href="#3-4-注意点" class="headerlink" title="3.4 注意点"></a>3.4 注意点</h2><p>我感觉这道题没有什么要注意的东西，就算要有吧，也就是要注意转移到下一个节点进行翻转的时候，定位要不能定next了，因为操作过后已经转移了，所以要在翻转前就给<code>cur-&gt;next</code>给标记上temp。</p>
<h2 id="3-5-代码实现"><a href="#3-5-代码实现" class="headerlink" title="3.5 代码实现"></a>3.5 代码实现</h2><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span> &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function">ListNode* <span class="title">reverseList</span><span class="params">(ListNode* head)</span> </span>&#123;</span><br><span class="line">        ListNode* temp = <span class="keyword">new</span> <span class="built_in">ListNode</span>(); <span class="comment">//临时节点，用来存储要操作的下一个节点的</span></span><br><span class="line">        ListNode* pre = <span class="literal">NULL</span>; <span class="comment">//指向头节点的前一个节点</span></span><br><span class="line">        ListNode* cur = head; <span class="comment">//指向头节点</span></span><br><span class="line">        <span class="keyword">while</span>(cur)&#123;</span><br><span class="line">            temp = cur-&gt;next; <span class="comment">//标记</span></span><br><span class="line">            cur-&gt;next = pre;  <span class="comment">//翻转</span></span><br><span class="line">            pre = cur; <span class="comment">//下一组</span></span><br><span class="line">            cur = temp; <span class="comment">//下一组</span></span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> pre;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

<h1 id="4-两两交换链表中的节点"><a href="#4-两两交换链表中的节点" class="headerlink" title="4. 两两交换链表中的节点"></a>4. 两两交换链表中的节点</h1><h2 id="相关题目-2"><a href="#相关题目-2" class="headerlink" title="相关题目"></a>相关题目</h2><p><img src="https://leetcode.cn/problems/reverse-linked-list/" alt="Problem 24 两两交换链表中的节点"></p>
<h2 id="4-1-复杂度"><a href="#4-1-复杂度" class="headerlink" title="4.1 复杂度"></a>4.1 复杂度</h2><p>时间复杂度：<code>O(n)</code><br>空间复杂度：<code>O(1)</code></p>
<h2 id="4-2-主要思想"><a href="#4-2-主要思想" class="headerlink" title="4.2 主要思想"></a>4.2 主要思想</h2><p>要关注好移动的顺序，这道题是很好的让人们能够关注流程顺序的一道题目。<br><img src="/images/LinkListturn.png"></p>
<h2 id="4-3-注意点"><a href="#4-3-注意点" class="headerlink" title="4.3 注意点"></a>4.3 注意点</h2><p>关注好移动的顺序</p>
<h2 id="4-4-代码实现"><a href="#4-4-代码实现" class="headerlink" title="4.4 代码实现"></a>4.4 代码实现</h2><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span> &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function">ListNode* <span class="title">swapPairs</span><span class="params">(ListNode* head)</span> </span>&#123;</span><br><span class="line">        ListNode* p = <span class="keyword">new</span> <span class="built_in">ListNode</span>(<span class="number">0</span>);</span><br><span class="line">        p-&gt;next = head;</span><br><span class="line">        ListNode* cur = p;</span><br><span class="line">        <span class="keyword">while</span>(cur-&gt;next != <span class="literal">nullptr</span> &amp;&amp; cur-&gt;next-&gt;next != <span class="literal">nullptr</span>)&#123;</span><br><span class="line">        ListNode* temp = cur-&gt;next; <span class="comment">//临时节点1</span></span><br><span class="line">        ListNode* temp1 = cur-&gt;next-&gt;next-&gt;next; <span class="comment">//临时节点2</span></span><br><span class="line">        cur-&gt;next = cur-&gt;next-&gt;next; <span class="comment">//第一步操作，头节点-&gt;第二个</span></span><br><span class="line">        cur-&gt;next-&gt;next = temp; <span class="comment">//第二步操作，第二个-&gt;第一个</span></span><br><span class="line">        cur-&gt;next-&gt;next-&gt;next = temp1; <span class="comment">//第三步操作，第一个-&gt;第三个</span></span><br><span class="line"></span><br><span class="line">        cur = cur-&gt;next-&gt;next;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> p-&gt;next;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

<h1 id="5-删除列表的倒数第n个节点"><a href="#5-删除列表的倒数第n个节点" class="headerlink" title="5. 删除列表的倒数第n个节点"></a>5. 删除列表的倒数第n个节点</h1><h2 id="相关题目-3"><a href="#相关题目-3" class="headerlink" title="相关题目"></a>相关题目</h2><p><img src="https://leetcode.cn/problems/remove-nth-node-from-end-of-list/" alt="Problem 19. 删除列表的倒数第n个节点"></p>
<h2 id="5-1-复杂度"><a href="#5-1-复杂度" class="headerlink" title="5.1 复杂度"></a>5.1 复杂度</h2><p>时间复杂度：<code>O(n)</code><br>空间复杂度：<code>O(1)</code></p>
<h2 id="5-2-主要思想"><a href="#5-2-主要思想" class="headerlink" title="5.2 主要思想"></a>5.2 主要思想</h2><p>还是双指针，删除这种东西好像最好双指针了，一个用来指代他的条件，另一个指针来指向要删除的值，具体而言在这道题上就是慢指针是用来指代值的，快指针的条件判断在于，倒数第几个就移动几次，终止条件本来从虚拟头节点出发到nullptr就遍历完了，那么我们删除倒数第几个就派出另一个往前先走几步就行了，那么先出发的那个到达nullptr的时候就是真正删除的那一个到达要删除的时候。 </p>
<h2 id="5-3-注意点"><a href="#5-3-注意点" class="headerlink" title="5.3 注意点"></a>5.3 注意点</h2><p>就是我们的前进的时候用while循环，其实<code>for(int i=0; i++; i&lt;n)</code>和<code>while(n--)</code>是等价的，但是要考虑他是否越界，所以要添加上<code>fast != null</code>就用while好像更好一点了。</p>
<h2 id="5-4-代码实现"><a href="#5-4-代码实现" class="headerlink" title="5.4 代码实现"></a>5.4 代码实现</h2><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span> &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function">ListNode* <span class="title">removeNthFromEnd</span><span class="params">(ListNode* head, <span class="type">int</span> n)</span> </span>&#123;</span><br><span class="line">        ListNode* dummyList = <span class="keyword">new</span> <span class="built_in">ListNode</span>();</span><br><span class="line">        dummyList-&gt;next = head;</span><br><span class="line">        ListNode* fast = head;</span><br><span class="line">        ListNode* slow = dummyList;</span><br><span class="line">		<span class="comment">//很好的判断条件，防止倒数第n个本来就是不存在的情况</span></span><br><span class="line">        <span class="keyword">while</span>(n-- &amp;&amp; fast != <span class="literal">nullptr</span>)&#123;</span><br><span class="line">            fast = fast-&gt;next;</span><br><span class="line">        &#125;</span><br><span class="line">		<span class="comment">// 一起前进</span></span><br><span class="line">        <span class="keyword">while</span>(fast != <span class="literal">nullptr</span>)&#123;</span><br><span class="line">            fast = fast-&gt;next;</span><br><span class="line">            slow = slow-&gt;next;</span><br><span class="line">        &#125;</span><br><span class="line">        ListNode* p = slow-&gt;next;</span><br><span class="line">        slow-&gt;next = p-&gt;next;</span><br><span class="line">        <span class="keyword">delete</span> p;</span><br><span class="line">        <span class="keyword">return</span> dummyList-&gt;next;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

<h1 id="6-链表相交"><a href="#6-链表相交" class="headerlink" title="6. 链表相交"></a>6. 链表相交</h1><h2 id="相关题目-4"><a href="#相关题目-4" class="headerlink" title="相关题目"></a>相关题目</h2><p><img src="https://leetcode.cn/problems/intersection-of-two-linked-lists-lcci/" alt="Problem 链表相交"></p>
<h2 id="6-1-复杂度"><a href="#6-1-复杂度" class="headerlink" title="6.1 复杂度"></a>6.1 复杂度</h2><p>时间复杂度：<code>O(n + m)</code><br>空间复杂度：<code>O(1)</code></p>
<h2 id="6-2-主要思想"><a href="#6-2-主要思想" class="headerlink" title="6.2 主要思想"></a>6.2 主要思想</h2><p>这道题告诉你之后难度不大，就是看看两个链表的部分是否相等就行了，怎么看呢，一个个移动，直到空为止，很容易知道应该是以最短的那个链表作为基准，因为最短的链表遍历完之后所有有可能的结果也就尘埃落定了。所以我们要做的第一步就是比对两个数组找出长度差值，之后才能够精准的进行定位。</p>
<h2 id="6-3-注意点"><a href="#6-3-注意点" class="headerlink" title="6.3 注意点"></a>6.3 注意点</h2><p>计算完长度之后，临时指针要重定向归于原来的头节点，不然他们计算完长度之后的状态是指向nullptr的</p>
<h2 id="6-4-代码实现"><a href="#6-4-代码实现" class="headerlink" title="6.4 代码实现"></a>6.4 代码实现</h2><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span> &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function">ListNode *<span class="title">getIntersectionNode</span><span class="params">(ListNode *headA, ListNode *headB)</span> </span>&#123;</span><br><span class="line">        ListNode* cur1 = headA;</span><br><span class="line">        ListNode* cur2 = headB;</span><br><span class="line">        <span class="type">int</span> lenA = <span class="number">0</span>, lenB = <span class="number">0</span>;</span><br><span class="line">			<span class="comment">//计算长度</span></span><br><span class="line">        <span class="keyword">while</span>(cur1 != <span class="literal">NULL</span>)&#123;</span><br><span class="line">            cur1 = cur1-&gt;next;</span><br><span class="line">            lenA++;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">while</span>(cur2 != <span class="literal">NULL</span>)&#123;</span><br><span class="line">            cur2 = cur2-&gt;next;</span><br><span class="line">            lenB++;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        cur1 = headA;</span><br><span class="line">        cur2 = headB;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span>(lenA &lt; lenB)&#123;</span><br><span class="line">            <span class="built_in">swap</span>(lenA, lenB);</span><br><span class="line">            <span class="built_in">swap</span>(cur1, cur2);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="type">int</span> gap = lenA - lenB;</span><br><span class="line">			<span class="comment">//移动到同一起跑线</span></span><br><span class="line">        <span class="keyword">while</span>(gap--)&#123;</span><br><span class="line">            cur1 = cur1-&gt;next;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">while</span>(cur1 != <span class="literal">nullptr</span>)&#123;</span><br><span class="line">            <span class="keyword">if</span>(cur1 == cur2)&#123;</span><br><span class="line">                <span class="keyword">return</span> cur1;</span><br><span class="line">            &#125;</span><br><span class="line">            cur1 = cur1-&gt;next;</span><br><span class="line">            cur2 = cur2-&gt;next;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">NULL</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<h1 id="7-环形链表"><a href="#7-环形链表" class="headerlink" title="7. 环形链表"></a>7. 环形链表</h1><h2 id="相关题目-5"><a href="#相关题目-5" class="headerlink" title="相关题目"></a>相关题目</h2><p><img src="https://leetcode.cn/problems/linked-list-cycle-ii/" alt="Problem 142. 环形链表"></p>
<h2 id="7-1-复杂度"><a href="#7-1-复杂度" class="headerlink" title="7.1 复杂度"></a>7.1 复杂度</h2><p>时间复杂度：<code>O(n)</code><br>空间复杂度：<code>O(1)</code></p>
<h2 id="7-2-主要思想"><a href="#7-2-主要思想" class="headerlink" title="7.2 主要思想"></a>7.2 主要思想</h2><p>这道题由两个部分组成，第一个部分是有没有环，第二个部分是环的入口到底在哪？ 首先有没有环的判断就是依据两个指针一快一慢的走，如果相遇了就能证明有环，但是这是一个必要证明，还得加上一个条件就是快指针走两步慢指针走一步，本质上就是一个追赶问题，<strong>快指针每次相对于慢指针多走了一步，那么就是链表中每一个格子都有能够遇上的机会。</strong>所以此时遇上和有环形成了一个充分必要的对应证明条件。 那么入口在哪呢，假设入口离起始点的距离为x，第一次相遇两指针在距离入口y处，环的长度为y+z，那么我们可以推断出，慢指针走了x+y距离，快指针走了x+n(y+z)。那么他们相遇的话，即x+y &#x3D; x+n(y+z)，我们要探究x是多少，即可以把等式变化为：x &#x3D; (n-1)(y+z)+z，那么因为 y+z表示一直在绕圈可以忽略掉 ，所以我们可以得出一个结论叫做，起点到入环点的位置和相遇点到入环点的位置是相等的。</p>
<blockquote>
<p>这里x一定没有绕环的论证在慢指针走一圈的时间快指针能走两圈，而快指针相对于慢指针每次走一步，也就是说快指针速度为2v，慢指针速度为v，快指针追上慢指针需要走的路程为y+z-a(不足一圈)，追上的时间为(y+z-a)&#x2F;(2v-v),慢指针走一圈的时间为(y+z)&#x2F;v，追上的时间小于慢指针走一圈的时间，所以一定能够追得上。</p>
</blockquote>
<h2 id="7-4-代码实现"><a href="#7-4-代码实现" class="headerlink" title="7.4 代码实现"></a>7.4 代码实现</h2><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span> &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function">ListNode *<span class="title">detectCycle</span><span class="params">(ListNode *head)</span> </span>&#123;</span><br><span class="line">        ListNode* fast = head;</span><br><span class="line">        ListNode* slow = head;</span><br><span class="line">        <span class="keyword">while</span>(fast != <span class="literal">NULL</span> &amp;&amp; fast-&gt;next != <span class="literal">NULL</span>) &#123;</span><br><span class="line">            slow = slow-&gt;next;</span><br><span class="line">            fast = fast-&gt;next-&gt;next;</span><br><span class="line">            <span class="comment">// 快慢指针相遇，此时从head 和 相遇点，同时查找直至相遇</span></span><br><span class="line">            <span class="keyword">if</span> (slow == fast) &#123;</span><br><span class="line">                ListNode* index1 = fast;</span><br><span class="line">                ListNode* index2 = head;</span><br><span class="line">                <span class="keyword">while</span> (index1 != index2) &#123;</span><br><span class="line">                    index1 = index1-&gt;next;</span><br><span class="line">                    index2 = index2-&gt;next;</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="keyword">return</span> index2; <span class="comment">// 返回环的入口</span></span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">NULL</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

      
    </div>

    
    
    
      <footer class="post-footer">
        <div class="post-eof"></div>
      </footer>
  </article>
  
  
  

      
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://daorongxing.gitee.io/post/42640/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="Daorong Xing">
      <meta itemprop="description" content="这是我的个人博客，记录计算机学习之路！">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="邢道荣的个人博客">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          
            <a href="/post/42640/" class="post-title-link" itemprop="url">JVM概述</a>
        </h2>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>

              <time title="创建时间：2022-11-24 16:25:39" itemprop="dateCreated datePublished" datetime="2022-11-24T16:25:39+08:00">2022-11-24</time>
            </span>
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="far fa-calendar-check"></i>
                </span>
                <span class="post-meta-item-text">更新于</span>
                <time title="修改时间：2022-11-25 16:11:07" itemprop="dateModified" datetime="2022-11-25T16:11:07+08:00">2022-11-25</time>
              </span>
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-folder"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/JVM/" itemprop="url" rel="index"><span itemprop="name">JVM</span></a>
                </span>
            </span>

          <br>
            <span class="post-meta-item" title="本文字数">
              <span class="post-meta-item-icon">
                <i class="far fa-file-word"></i>
              </span>
                <span class="post-meta-item-text">本文字数：</span>
              <span>298</span>
            </span>
            <span class="post-meta-item" title="阅读时长">
              <span class="post-meta-item-icon">
                <i class="far fa-clock"></i>
              </span>
                <span class="post-meta-item-text">阅读时长 &asymp;</span>
              <span>1 分钟</span>
            </span>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
          <h1 id="一-Java语言及JVM的概述"><a href="#一-Java语言及JVM的概述" class="headerlink" title="一.Java语言及JVM的概述"></a>一.Java语言及JVM的概述</h1><h2 id="1-Java的优点"><a href="#1-Java的优点" class="headerlink" title="1. Java的优点"></a>1. Java的优点</h2><ul>
<li>一次编译，到处运行。</li>
<li>内存管理访问机制相对安全，尽可能避免内存泄漏和数组指针越界等问题。</li>
<li>热点代码检测，编译优化<blockquote>
<p>编译优化：<code>String c = &quot;a&quot; + &quot;b&quot;; </code> &#x3D;&#x3D;&gt;<code>String c = &quot;ab&quot;;</code></p>
</blockquote>
</li>
<li>第三方类库丰富，开源功能强大</li>
<li>多态</li>
</ul>
<h2 id="2-JVM"><a href="#2-JVM" class="headerlink" title="2.JVM"></a>2.JVM</h2><p>​		jvm ( Java visual machine )，java虚拟机， 具有控制java内存的能力，可以让程序员在编写程序时享受自动内存管理的诸多优势，但是也需要警惕因为各种原因出现的内存泄露和溢出的问题。</p>
<p> 下图为Java技术体系的三个概念的关系：</p>
<p><img src="/images/JVM.png" alt="image-20221118174353103"></p>

      
    </div>

    
    
    
      <footer class="post-footer">
        <div class="post-eof"></div>
      </footer>
  </article>
  
  
  

      
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://daorongxing.gitee.io/post/27692/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="Daorong Xing">
      <meta itemprop="description" content="这是我的个人博客，记录计算机学习之路！">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="邢道荣的个人博客">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          
            <a href="/post/27692/" class="post-title-link" itemprop="url">JVM内存结构</a>
        </h2>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>
              

              <time title="创建时间：2022-11-24 16:25:39 / 修改时间：18:37:53" itemprop="dateCreated datePublished" datetime="2022-11-24T16:25:39+08:00">2022-11-24</time>
            </span>
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-folder"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/JVM/" itemprop="url" rel="index"><span itemprop="name">JVM</span></a>
                </span>
            </span>

          <br>
            <span class="post-meta-item" title="本文字数">
              <span class="post-meta-item-icon">
                <i class="far fa-file-word"></i>
              </span>
                <span class="post-meta-item-text">本文字数：</span>
              <span>8.4k</span>
            </span>
            <span class="post-meta-item" title="阅读时长">
              <span class="post-meta-item-icon">
                <i class="far fa-clock"></i>
              </span>
                <span class="post-meta-item-text">阅读时长 &asymp;</span>
              <span>8 分钟</span>
            </span>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
          <h1 id="JVM内存结构"><a href="#JVM内存结构" class="headerlink" title="JVM内存结构"></a>JVM内存结构</h1><p><img src="/images/%E5%86%85%E5%AD%98%E7%BB%93%E6%9E%84.png"></p>
<p>内存结构基本示意图：</p>
<p><img src="/images/MemoryStructure.png"></p>
<h2 id="1-程序计数器"><a href="#1-程序计数器" class="headerlink" title="1. 程序计数器"></a>1. 程序计数器</h2><h3 id="1-1-定义"><a href="#1-1-定义" class="headerlink" title="1.1 定义"></a>1.1 定义</h3><p>行号指示器，字节码解释器运行时通过改变计数器值来选取下一条需要执行的字节码指令。</p>
<h3 id="1-2-特点"><a href="#1-2-特点" class="headerlink" title="1.2 特点"></a>1.2 特点</h3><p>每条线程都需要有独立的程序计数器，<strong>线程私有</strong></p>
<p><mark>唯一一个</mark>不会出现<font color=red>OutOfMemoryError</font>情况的内存区域</p>
<h2 id="2-栈"><a href="#2-栈" class="headerlink" title="2. 栈"></a>2. 栈</h2><h3 id="2-1-栈和栈帧"><a href="#2-1-栈和栈帧" class="headerlink" title="2.1 栈和栈帧"></a>2.1 栈和栈帧</h3><ul>
<li><p><strong>栈：线程运行所需要的内存空间</strong></p>
<ol>
<li>线程生命周期和栈的生命周期相同</li>
<li>栈的内存空间和线程数呈负相关</li>
</ol>
</li>
<li><p><strong>栈帧：每个方法运行时所需要的内存</strong></p>
<ol>
<li>存储局部变量表，操作数栈，动态连接，方法出口等</li>
<li>生命周期和方法相同，每个方法调用直到执行完毕，就对应着栈帧入栈到出栈的过程。</li>
</ol>
</li>
</ul>
<blockquote>
<p>局部变量表：用于存储方法参数和局部变量等 </p>
</blockquote>
<h3 id="2-2-栈的线程安全"><a href="#2-2-栈的线程安全" class="headerlink" title="2.2 栈的线程安全"></a>2.2 栈的线程安全</h3><p><font size=5 color="red"><strong>！！！方法内的局部变量是否涉及线程安全：</strong></font></p>
<blockquote>
<p>线程安全：保证多个线程同时对某一对象或资源进行操作时不会出错</p>
</blockquote>
<ol>
<li>如果方法内局部变量没有<mark>逃离方法作用范围</mark>，那么他是**<u>线程安全</u>**的:</li>
</ol>
<p>​		没有逃离方法的作用范围，局部变量无逃逸，无法被其他线程访问。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">m1</span><span class="params">()</span> &#123;</span><br><span class="line">    <span class="type">StringBuilder</span> <span class="variable">sb</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">StringBuilder</span>();</span><br><span class="line">    sb.append(<span class="number">1</span>);</span><br><span class="line">    sb.append(<span class="number">2</span>);</span><br><span class="line">    sb.append(<span class="number">3</span>);</span><br><span class="line">    System.out.println(sb.toString());</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<ol start="2">
<li><p>如果局部变量引用了对象，并<mark>逃离方法的作用范围</mark>，那么他是**<u>不安全</u>**的:</p>
<p>作为参数传参进入，可以会有被别的对象调用的风险。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">m2</span><span class="params">(StringBuilder sb)</span> &#123;</span><br><span class="line">    sb.append(<span class="number">1</span>);</span><br><span class="line">    sb.append(<span class="number">2</span>);</span><br><span class="line">    sb.append(<span class="number">3</span>);</span><br><span class="line">    System.out.println(sb.toString());</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li>
</ol>
<p>​		存在返回值，有可能被他人调用：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> StringBuilder <span class="title function_">m3</span><span class="params">()</span> &#123;</span><br><span class="line">    <span class="type">StringBuilder</span> <span class="variable">sb</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">StringBuilder</span>();</span><br><span class="line">    sb.append(<span class="number">1</span>);</span><br><span class="line">    sb.append(<span class="number">2</span>);</span><br><span class="line">    sb.append(<span class="number">3</span>);</span><br><span class="line">    <span class="keyword">return</span> sb;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h3 id="2-3-栈的有关异常"><a href="#2-3-栈的有关异常" class="headerlink" title="2.3 栈的有关异常"></a>2.3 栈的有关异常</h3><ol>
<li><strong><font color=red>StackOverFlowError</font></strong>: 线程请求的栈深度大于虚拟机所允许的深度</li>
</ol>
<p>​			一般出现原因为<mark>递归</mark>调用<mark>无设置终止条件</mark>或者<mark>终止条件无法达到</mark></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Demo1_2</span> &#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="type">int</span> count;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            method1();</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Throwable e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">            System.out.println(count);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">method1</span><span class="params">()</span> &#123;</span><br><span class="line">        count++;</span><br><span class="line">        method1(); <span class="comment">//递归调用自己，但是没有设置终止条件</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<ol start="2">
<li><font color=red><strong>OutOfMemoryError</strong></font>: 栈无法申请到足够多的内存空间时</li>
</ol>
<p>​			与内存空间有关。</p>
<h2 id="3-本地方法栈"><a href="#3-本地方法栈" class="headerlink" title="3. 本地方法栈"></a>3. 本地方法栈</h2><p>为本地方法运行提供空间的内存空间</p>
<p><code>public native int hashCode();</code></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">equals</span><span class="params">(Object obj)</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> (<span class="built_in">this</span> == obj);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>含有**<u>native关键字</u>**修饰的方法<br>    object: motify, add, hashcode….</p>
<h2 id="4-堆"><a href="#4-堆" class="headerlink" title="4. 堆"></a>4. 堆</h2><h3 id="4-1-定义"><a href="#4-1-定义" class="headerlink" title="4.1 定义"></a>4.1 定义</h3><p>是被所有<mark>线程共享</mark>的一块区域，在<mark>虚拟机启动</mark>的时候自动创建，目的是<mark>存放对象实例(new)</mark>。</p>
<h3 id="4-2-特点"><a href="#4-2-特点" class="headerlink" title="4.2 特点"></a>4.2 特点</h3><ul>
<li>线程共享，需要考虑线程安全的问题</li>
<li>在虚拟机启动的时候自动创建</li>
<li>有垃圾回收机制</li>
</ul>
<h3 id="4-3-堆内存溢出"><a href="#4-3-堆内存溢出" class="headerlink" title="4.3 堆内存溢出"></a>4.3 堆内存溢出</h3><p> <strong>java.lang.OutOfMemoryError:  Java heap space：</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">    <span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        List&lt;String&gt; list = <span class="keyword">new</span> <span class="title class_">ArrayList</span>&lt;&gt;();</span><br><span class="line">        <span class="type">String</span> <span class="variable">a</span> <span class="operator">=</span> <span class="string">&quot;hello&quot;</span>;</span><br><span class="line">        <span class="keyword">while</span> (<span class="literal">true</span>) &#123;</span><br><span class="line">            list.add(a); <span class="comment">// hello, hellohello, hellohellohellohello ...</span></span><br><span class="line">            a = a + a;  <span class="comment">// hellohellohellohello</span></span><br><span class="line">            i++;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125; <span class="keyword">catch</span> (Throwable e) &#123;</span><br><span class="line">        e.printStackTrace();</span><br><span class="line">        System.out.println(i);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h3 id="4-4-堆内存诊断"><a href="#4-4-堆内存诊断" class="headerlink" title="4.4 堆内存诊断"></a>4.4 堆内存诊断</h3><ul>
<li><strong>JPS： 查看系统中有哪些java进程</strong></li>
</ul>
<p>直接在<code>Terminal</code>窗口输入jps中可得到下图结果。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//进程编号         //进程名称</span></span><br><span class="line"><span class="number">11936</span>              Jps</span><br><span class="line"><span class="number">13664</span>              Demo1_4</span><br><span class="line"><span class="number">436</span>              </span><br><span class="line"><span class="number">9388</span>              Launcher</span><br></pre></td></tr></table></figure>

<ul>
<li><strong>Jmap：观测指定进程的内存情况</strong></li>
</ul>
<p>用<code> jmap -heap + 进程编号</code>查看当前进程的运行情况</p>
<img src="/images/jmap1.png" style="zoom: 67%;" title="堆配置信息" align="left"/>

<figure class="highlight plaintext"><figcaption><span>Configuration```： 堆配置信息</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">```MaxHeapSize```： 最大堆空间</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">&lt;img src=&quot;/images/jmap2.png&quot; style=&quot;zoom:67%;&quot; align=&quot;left&quot;/&gt;</span><br><span class="line"></span><br><span class="line">```Heap Usage```： 堆使用情况</span><br><span class="line"></span><br><span class="line">```used```： 已经使用</span><br><span class="line"></span><br><span class="line">```free```： 未使用</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">- **Jconsole：图形化页面监测工具，可以实现动态的检测**</span><br><span class="line"></span><br><span class="line">&lt;img src=&quot;/images/jconsole.png&quot; style=&quot;zoom:50%;&quot; align=&quot;left&quot; /&gt;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">## 5. 方法区</span><br><span class="line"></span><br><span class="line">### 5.1 作用</span><br><span class="line"></span><br><span class="line">存储被虚拟机加载的类型信息，常量，静态变量，代码缓存等数据</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">### 5.2  JVM1.8和1.6不同的组成</span><br><span class="line"></span><br><span class="line">![](/images/MethodArea.png)</span><br><span class="line"></span><br><span class="line">主要变化：实现方式由永久代转变为了元空间，常量池中```StringTable```放到了堆内存中。</span><br><span class="line"></span><br><span class="line">原因：永久代垃圾回收机制为```Full GC```，回收效率低，易导致临时变量占据空间过多，堆内存中垃圾回收机制较永久代灵活</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">### 5.3 方法区内存溢出</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">```java</span><br><span class="line">    public static void main(String[] args) &#123;</span><br><span class="line">        int j = 0;</span><br><span class="line">        try &#123;</span><br><span class="line">            Demo1_8 test = new Demo1_8();</span><br><span class="line">            for (int i = 0; i &lt; 10000; i++, j++) &#123;</span><br><span class="line">                // ClassWriter 作用是生成类的二进制字节码</span><br><span class="line">                ClassWriter cw = new ClassWriter(0);</span><br><span class="line">                // 版本号， public， 类名, 包名, 父类， 接口</span><br><span class="line">                cw.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC, &quot;Class&quot; + i, null, &quot;java/lang/Object&quot;, null);</span><br><span class="line">                // 返回 byte[]</span><br><span class="line">                byte[] code = cw.toByteArray();</span><br><span class="line">                // 执行了类的加载</span><br><span class="line">                test.defineClass(&quot;Class&quot; + i, code, 0, code.length); // Class 对象</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; finally &#123;</span><br><span class="line">            System.out.println(j);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>

<ul>
<li>1.8 元空间内存溢出</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// java.lang.OutOfMemoryError: Metaspace</span></span><br><span class="line"><span class="comment">// -XX:MaxMetaspaceSize=8m</span></span><br></pre></td></tr></table></figure>



<ul>
<li>1.6 永久代内存溢出</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// java.lang.OutOfMemoryError: PermGen space</span></span><br><span class="line"><span class="comment">// -XX:MaxPermSize=8m</span></span><br></pre></td></tr></table></figure>



<h2 id="6-常量池"><a href="#6-常量池" class="headerlink" title="6. 常量池"></a>6. 常量池</h2><p>作用：用于存储信息，本身时二进制字节码对象，常量池中的信息，都会被加载到运行时常量池中， 这时 a b ab 都是常量池中的符号，还没有变为 java 字符串对象</p>
<p>通过<code>javap -v HelloWorld.class</code>可以获得class二进制字节码文件的基本信息</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br></pre></td><td class="code"><pre><span class="line">  <span class="comment">// 基本配置信息</span></span><br><span class="line">  Last modified <span class="number">2022</span>-<span class="number">11</span>-<span class="number">24</span>; size <span class="number">442</span> bytes</span><br><span class="line">  MD5 checksum 103606e24ec918e862312533fda15bbc</span><br><span class="line">  Compiled from <span class="string">&quot;HelloWorld.java&quot;</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">cn</span>.itcast.jvm.t5.HelloWorld</span><br><span class="line">  minor version: <span class="number">0</span></span><br><span class="line">  major version: <span class="number">52</span></span><br><span class="line">  flags: ACC_PUBLIC, ACC_SUPER</span><br><span class="line">      <span class="comment">//常量池</span></span><br><span class="line">Constant pool:</span><br><span class="line">   #<span class="number">1</span> = Methodref          #<span class="number">6.</span>#<span class="number">15</span>         <span class="comment">// java/lang/Object.&quot;&lt;init&gt;&quot;:()V</span></span><br><span class="line">   #<span class="number">2</span> = Fieldref           #<span class="number">16.</span>#<span class="number">17</span>        <span class="comment">// java/lang/System.out:Ljava/io/PrintStream;</span></span><br><span class="line">   #<span class="number">3</span> = String             #<span class="number">18</span>            <span class="comment">// hello world</span></span><br><span class="line">   #<span class="number">4</span> = Methodref          #<span class="number">19.</span>#<span class="number">20</span>        <span class="comment">// java/io/PrintStream.println:(Ljava/lang/String;)V</span></span><br><span class="line">   #<span class="number">5</span> = Class              #<span class="number">21</span>            <span class="comment">// cn/itcast/jvm/t5/HelloWorld</span></span><br><span class="line">   #<span class="number">6</span> = Class              #<span class="number">22</span>            <span class="comment">// java/lang/Object</span></span><br><span class="line">   #<span class="number">7</span> = Utf8               &lt;init&gt;</span><br><span class="line">   #<span class="number">8</span> = Utf8               ()V</span><br><span class="line">   #<span class="number">9</span> = Utf8               Code</span><br><span class="line">  #<span class="number">10</span> = Utf8               LineNumberTable</span><br><span class="line">  #<span class="number">11</span> = Utf8               main</span><br><span class="line">  #<span class="number">12</span> = Utf8               ([Ljava/lang/String;)V</span><br><span class="line">  #<span class="number">13</span> = Utf8               SourceFile</span><br><span class="line">  #<span class="number">14</span> = Utf8               HelloWorld.java</span><br><span class="line">  #<span class="number">15</span> = NameAndType        #<span class="number">7</span>:#<span class="number">8</span>          <span class="comment">// &quot;&lt;init&gt;&quot;:()V</span></span><br><span class="line">  #<span class="number">16</span> = Class              #<span class="number">23</span>            <span class="comment">// java/lang/System</span></span><br><span class="line">  #<span class="number">17</span> = NameAndType        #<span class="number">24</span>:#<span class="number">25</span>        <span class="comment">// out:Ljava/io/PrintStream;</span></span><br><span class="line">  #<span class="number">18</span> = Utf8               hello world</span><br><span class="line">  #<span class="number">19</span> = Class              #<span class="number">26</span>            <span class="comment">// java/io/PrintStream</span></span><br><span class="line">  #<span class="number">20</span> = NameAndType        #<span class="number">27</span>:#<span class="number">28</span>        <span class="comment">// println:(Ljava/lang/String;)V</span></span><br><span class="line">  #<span class="number">21</span> = Utf8               cn/itcast/jvm/t5/HelloWorld</span><br><span class="line">  #<span class="number">22</span> = Utf8               java/lang/Object</span><br><span class="line">  #<span class="number">23</span> = Utf8               java/lang/System</span><br><span class="line">  #<span class="number">24</span> = Utf8               out</span><br><span class="line">  #<span class="number">25</span> = Utf8               Ljava/io/PrintStream;</span><br><span class="line">  #<span class="number">26</span> = Utf8               java/io/PrintStream</span><br><span class="line">  #<span class="number">27</span> = Utf8               println</span><br><span class="line">  #<span class="number">28</span> = Utf8               (Ljava/lang/String;)V</span><br><span class="line">                             </span><br><span class="line">   <span class="comment">// 类方法定义</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="keyword">public</span> cn.itcast.jvm.t5.HelloWorld();</span><br><span class="line">    descriptor: ()V</span><br><span class="line">    flags: ACC_PUBLIC</span><br><span class="line">    Code:</span><br><span class="line">      stack=<span class="number">1</span>, locals=<span class="number">1</span>, args_size=<span class="number">1</span></span><br><span class="line">         <span class="number">0</span>: aload_0</span><br><span class="line">         <span class="number">1</span>: invokespecial #<span class="number">1</span>                  <span class="comment">// Method java/lang/Object.&quot;&lt;init&gt;&quot;:()V</span></span><br><span class="line">         <span class="number">4</span>: <span class="keyword">return</span></span><br><span class="line">      LineNumberTable:</span><br><span class="line">        line <span class="number">4</span>: <span class="number">0</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(java.lang.String[])</span>;</span><br><span class="line">    descriptor: ([Ljava/lang/String;)V</span><br><span class="line">    flags: ACC_PUBLIC, ACC_STATIC</span><br><span class="line">    Code:</span><br><span class="line">      stack=<span class="number">2</span>, locals=<span class="number">1</span>, args_size=<span class="number">1</span></span><br><span class="line">         <span class="number">0</span>: getstatic     #<span class="number">2</span>                  <span class="comment">// Field java/lang/System.out:Ljava/io/PrintStream;</span></span><br><span class="line">         <span class="number">3</span>: ldc           #<span class="number">3</span>                  <span class="comment">// String hello world</span></span><br><span class="line">         <span class="number">5</span>: invokevirtual #<span class="number">4</span>                  <span class="comment">// Method java/io/PrintStream.println:(Ljava/lang/String;)V</span></span><br><span class="line">         <span class="number">8</span>: <span class="keyword">return</span></span><br><span class="line">      LineNumberTable:</span><br><span class="line">        line <span class="number">6</span>: <span class="number">0</span></span><br><span class="line">        line <span class="number">7</span>: <span class="number">8</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>主要操作流程： 根据指令后面编号去查找相应内容</p>
<h2 id="7-StringTable"><a href="#7-StringTable" class="headerlink" title="7. StringTable"></a>7. StringTable</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        <span class="type">String</span> <span class="variable">s1</span> <span class="operator">=</span> <span class="string">&quot;a&quot;</span>;</span><br><span class="line">        <span class="type">String</span> <span class="variable">s2</span> <span class="operator">=</span> <span class="string">&quot;b&quot;</span>;</span><br><span class="line">        <span class="type">String</span> <span class="variable">s3</span> <span class="operator">=</span> <span class="string">&quot;a&quot;</span> + <span class="string">&quot;b&quot;</span>; <span class="comment">// ab</span></span><br><span class="line">        <span class="type">String</span> <span class="variable">s4</span> <span class="operator">=</span> s1 + s2;   <span class="comment">// new String(&quot;ab&quot;)</span></span><br><span class="line">        <span class="type">String</span> <span class="variable">s5</span> <span class="operator">=</span> <span class="string">&quot;ab&quot;</span>;</span><br><span class="line">        <span class="type">String</span> <span class="variable">s6</span> <span class="operator">=</span> s4.intern();</span><br><span class="line"></span><br><span class="line"><span class="comment">// 问</span></span><br><span class="line">        System.out.println(s3 == s4); <span class="comment">// false</span></span><br><span class="line">        System.out.println(s3 == s5); <span class="comment">// true</span></span><br><span class="line">        System.out.println(s3 == s6); <span class="comment">// true</span></span><br><span class="line"></span><br><span class="line">        <span class="type">String</span> <span class="variable">x2</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">String</span>(<span class="string">&quot;c&quot;</span>) + <span class="keyword">new</span> <span class="title class_">String</span>(<span class="string">&quot;d&quot;</span>); <span class="comment">// new String(&quot;cd&quot;)</span></span><br><span class="line">        x2.intern();</span><br><span class="line">        <span class="type">String</span> <span class="variable">x1</span> <span class="operator">=</span> <span class="string">&quot;cd&quot;</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 问，如果调换了【最后两行代码】的位置呢，如果是jdk1.6呢</span></span><br><span class="line">        System.out.println(x1 == x2);</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>

<h3 id="7-1-常量池与串池之间的关系"><a href="#7-1-常量池与串池之间的关系" class="headerlink" title="7.1 常量池与串池之间的关系"></a>7.1 常量池与串池之间的关系</h3><p>常量池中存储的信息只是作为一个符号，通过方法调用（<code>String a = &quot;a&quot;</code>）或引用的时候才能真正的成为一个对象，而这时候如果串池中没有该对象的时候，将对象放入串池</p>
<p><mark>懒惰性：用到了才会在串池中创建，没有用到不会创建<strong>（延迟加载）</strong></mark></p>
<p>HashCode结构</p>
<h3 id="7-2-字符串拼接"><a href="#7-2-字符串拼接" class="headerlink" title="7.2 字符串拼接"></a>7.2 字符串拼接</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">String</span> <span class="variable">s1</span> <span class="operator">=</span> <span class="string">&quot;a&quot;</span>;</span><br><span class="line"><span class="type">String</span> <span class="variable">s2</span> <span class="operator">=</span> <span class="string">&quot;b&quot;</span>;</span><br><span class="line"><span class="type">String</span> <span class="variable">s3</span> <span class="operator">=</span> s1 + s2;</span><br><span class="line"><span class="type">String</span> <span class="variable">s4</span> <span class="operator">=</span> <span class="string">&quot;ab&quot;</span>;</span><br><span class="line"><span class="comment">// new StringBuilder().append(&quot;a&quot;).append(&quot;b&quot;).toString()-&gt; new String(&quot;ab&quot;)</span></span><br><span class="line"><span class="comment">// toString()方法生成了一个新的String对象</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> s3 == s4; <span class="comment">//false</span></span><br></pre></td></tr></table></figure>



<h3 id="7-3-编译期优化"><a href="#7-3-编译期优化" class="headerlink" title="7.3 编译期优化"></a>7.3 编译期优化</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">String</span> <span class="variable">s1</span> <span class="operator">=</span> <span class="string">&quot;a&quot;</span>;</span><br><span class="line"><span class="type">String</span> <span class="variable">s2</span> <span class="operator">=</span> <span class="string">&quot;b&quot;</span>;</span><br><span class="line"><span class="type">String</span> <span class="variable">s3</span> <span class="operator">=</span> <span class="string">&quot;a&quot;</span> + <span class="string">&quot;b&quot;</span>; <span class="comment">//编译期的优化：两个常量之和是确定的</span></span><br><span class="line"><span class="type">String</span> <span class="variable">s4</span> <span class="operator">=</span> <span class="string">&quot;ab&quot;</span>;</span><br><span class="line"><span class="keyword">return</span> s3 == s4 <span class="comment">//true</span></span><br></pre></td></tr></table></figure>



<h3 id="7-4-intern-方法"><a href="#7-4-intern-方法" class="headerlink" title="7.4 intern()方法"></a>7.4 intern()方法</h3><ul>
<li>1.8</li>
</ul>
<p>将字符串对象放入串池，有则不会放入，无则放入后返回</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line"></span><br><span class="line">   </span><br><span class="line">    <span class="type">String</span> <span class="variable">s</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">String</span>(<span class="string">&quot;a&quot;</span>) + <span class="keyword">new</span> <span class="title class_">String</span>(<span class="string">&quot;b&quot;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 堆  new String(&quot;a&quot;)   new String(&quot;b&quot;) new String(&quot;ab&quot;)</span></span><br><span class="line">    <span class="type">String</span> <span class="variable">s2</span> <span class="operator">=</span> s.intern(); <span class="comment">// 将这个字符串对象尝试放入串池，如果有则并不会放入，如果没有则放入串池， 会把串池中的对象返回</span></span><br><span class="line"> 	<span class="type">String</span> <span class="variable">x</span> <span class="operator">=</span> <span class="string">&quot;ab&quot;</span>;</span><br><span class="line">    System.out.println( s2 == x); <span class="comment">//true</span></span><br><span class="line">    System.out.println( s == x ); <span class="comment">//true</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<ul>
<li>1.6</li>
</ul>
<p>地址复制后放入串池（和原来的地址不相同）</p>
<p>public static void main(String[] args) {</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">String</span> <span class="variable">s</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">String</span>(<span class="string">&quot;a&quot;</span>) + <span class="keyword">new</span> <span class="title class_">String</span>(<span class="string">&quot;b&quot;</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 堆  new String(&quot;a&quot;)   new String(&quot;b&quot;) new String(&quot;ab&quot;)</span></span><br><span class="line"><span class="type">String</span> <span class="variable">s2</span> <span class="operator">=</span> s.intern(); <span class="comment">// 将这个字符串对象尝试放入串池，如果有则并不会放入，如果没有则放入串池， 会把串池中的对象返回</span></span><br><span class="line"><span class="type">String</span> <span class="variable">x</span> <span class="operator">=</span> <span class="string">&quot;ab&quot;</span>;</span><br><span class="line">System.out.println( s2 == x); <span class="comment">//true</span></span><br><span class="line">System.out.println( s == x ); <span class="comment">//false   因为s2是复制的，和原来地址并不一样</span></span><br></pre></td></tr></table></figure>
<p>}</p>
<h3 id="7-5-性能调优"><a href="#7-5-性能调优" class="headerlink" title="7.5 性能调优"></a>7.5 性能调优</h3><ul>
<li>调整-XX:StringTableSize&#x3D;桶个数：桶个数多有利于提高效率</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> IOException &#123;</span><br><span class="line">    <span class="keyword">try</span> (<span class="type">BufferedReader</span> <span class="variable">reader</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">BufferedReader</span>(<span class="keyword">new</span> <span class="title class_">InputStreamReader</span>(<span class="keyword">new</span> <span class="title class_">FileInputStream</span>(<span class="string">&quot;linux.words&quot;</span>), <span class="string">&quot;utf-8&quot;</span>))) &#123;</span><br><span class="line">        <span class="type">String</span> <span class="variable">line</span> <span class="operator">=</span> <span class="literal">null</span>;</span><br><span class="line">        <span class="type">long</span> <span class="variable">start</span> <span class="operator">=</span> System.nanoTime();</span><br><span class="line">        <span class="keyword">while</span> (<span class="literal">true</span>) &#123;</span><br><span class="line">            line = reader.readLine();</span><br><span class="line">            <span class="keyword">if</span> (line == <span class="literal">null</span>) &#123;</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            line.intern();</span><br><span class="line">        &#125;</span><br><span class="line">        System.out.println(<span class="string">&quot;cost:&quot;</span> + (System.nanoTime() - start) / <span class="number">1000000</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<ul>
<li>考虑串是否入池：重复字符串入池有助于提高效率</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> IOException &#123;</span><br><span class="line"></span><br><span class="line">    List&lt;String&gt; address = <span class="keyword">new</span> <span class="title class_">ArrayList</span>&lt;&gt;();</span><br><span class="line">    System.in.read();</span><br><span class="line">    <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">0</span>; i &lt; <span class="number">10</span>; i++) &#123;</span><br><span class="line">        <span class="keyword">try</span> (<span class="type">BufferedReader</span> <span class="variable">reader</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">BufferedReader</span>(<span class="keyword">new</span> <span class="title class_">InputStreamReader</span>(<span class="keyword">new</span> <span class="title class_">FileInputStream</span>(<span class="string">&quot;linux.words&quot;</span>), <span class="string">&quot;utf-8&quot;</span>))) &#123;</span><br><span class="line">            <span class="type">String</span> <span class="variable">line</span> <span class="operator">=</span> <span class="literal">null</span>;</span><br><span class="line">            <span class="type">long</span> <span class="variable">start</span> <span class="operator">=</span> System.nanoTime();</span><br><span class="line">            <span class="keyword">while</span> (<span class="literal">true</span>) &#123;</span><br><span class="line">                line = reader.readLine();</span><br><span class="line">                <span class="keyword">if</span>(line == <span class="literal">null</span>) &#123;</span><br><span class="line">                    <span class="keyword">break</span>;</span><br><span class="line">                &#125;</span><br><span class="line">                address.add(line.intern());</span><br><span class="line">            &#125;</span><br><span class="line">            System.out.println(<span class="string">&quot;cost:&quot;</span> +(System.nanoTime()-start)/<span class="number">1000000</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    System.in.read();</span><br></pre></td></tr></table></figure>

<h2 id="8-直接内存"><a href="#8-直接内存" class="headerlink" title="8. 直接内存"></a>8. 直接内存</h2><h3 id="8-1-作用"><a href="#8-1-作用" class="headerlink" title="8.1 作用"></a>8.1 作用</h3><p>是一种操作系统的内存，可以通过NIO中的directBuffer对象来实现内存调用的效率提高</p>
<p>直接用buffer调用需要通过系统缓冲区和Java缓冲区，而directMomery可以直接访问</p>
<h3 id="8-2-特点"><a href="#8-2-特点" class="headerlink" title="8.2 特点"></a>8.2 特点</h3><ol>
<li>分配回收成本高，读写性能高</li>
<li>和系统内存相关，和java本身堆大小无关</li>
</ol>
<h3 id="8-3-内存释放"><a href="#8-3-内存释放" class="headerlink" title="8.3 内存释放"></a>8.3 内存释放</h3><p>通过unsafe对象对于directMomery对象的调用</p>

      
    </div>

    
    
    
      <footer class="post-footer">
        <div class="post-eof"></div>
      </footer>
  </article>
  
  
  

      
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://daorongxing.gitee.io/post/32766/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="Daorong Xing">
      <meta itemprop="description" content="这是我的个人博客，记录计算机学习之路！">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="邢道荣的个人博客">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          
            <a href="/post/32766/" class="post-title-link" itemprop="url">数组</a>
        </h2>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>
              

              <time title="创建时间：2022-11-24 16:25:39 / 修改时间：18:37:34" itemprop="dateCreated datePublished" datetime="2022-11-24T16:25:39+08:00">2022-11-24</time>
            </span>
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-folder"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/%E7%AE%97%E6%B3%95/" itemprop="url" rel="index"><span itemprop="name">算法</span></a>
                </span>
            </span>

          <br>
            <span class="post-meta-item" title="本文字数">
              <span class="post-meta-item-icon">
                <i class="far fa-file-word"></i>
              </span>
                <span class="post-meta-item-text">本文字数：</span>
              <span>5.3k</span>
            </span>
            <span class="post-meta-item" title="阅读时长">
              <span class="post-meta-item-icon">
                <i class="far fa-clock"></i>
              </span>
                <span class="post-meta-item-text">阅读时长 &asymp;</span>
              <span>5 分钟</span>
            </span>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
          <h1 id="1-数组的基础定义"><a href="#1-数组的基础定义" class="headerlink" title="1. 数组的基础定义"></a>1. 数组的基础定义</h1><ul>
<li>数组的下标是从0开始的</li>
<li>数组中的地址是连续的</li>
</ul>
<p>要删除数组中的元素只能用替换去实现，无法直接删去</p>
<hr>
<h1 id="2-二分法"><a href="#2-二分法" class="headerlink" title="2. 二分法"></a>2. 二分法</h1><h2 id="相关题目"><a href="#相关题目" class="headerlink" title="相关题目"></a>相关题目</h2><ul>
<li>例题</li>
</ul>
<p><a target="_blank" rel="noopener" href="https://leetcode.cn/problems/binary-search/description/">Problem 704. 二分查找</a></p>
<ul>
<li>类似参考题目：</li>
</ul>
<p><a target="_blank" rel="noopener" href="https://leetcode.cn/problems/search-insert-position/">Problem 35.搜索插入位置 </a></p>
<p><a target="_blank" rel="noopener" href="https://leetcode.cn/problems/find-first-and-last-position-of-element-in-sorted-array/">Problem 34.在排序数组中查找元素的第一个和最后一个位置</a></p>
<h2 id="2-1-使用条件"><a href="#2-1-使用条件" class="headerlink" title="2.1 使用条件"></a>2.1 使用条件</h2><p>在求解寻找数组中的元素，或者满足条件的值会出现在数组的范围内（如求平方根）等内容时可使用；</p>
<p>使用时数组需满足如下条件（或变化后）：</p>
<ul>
<li>数组升序或者降序排列，即有序数组</li>
<li>数组中无重复项的出现</li>
</ul>
<h2 id="2-2-时间复杂度"><a href="#2-2-时间复杂度" class="headerlink" title="2.2 时间复杂度"></a>2.2 时间复杂度</h2><ul>
<li>暴力解法时间复杂度：<code>O(n)</code></li>
<li>二分法时间复杂度：<code>O(logn)</code></li>
</ul>
<h2 id="2-3-主要思想"><a href="#2-3-主要思想" class="headerlink" title="2.3 主要思想"></a>2.3 主要思想</h2><p>通过在有序数组中<strong>划分中间值</strong>，判断所求值与中间值之间的关系，较暴力解法可以<strong>直接排除掉</strong>一些不在范围之内的比较，提升了运行效率。</p>
<p><mark>有序数组：索引定位数据，索引的大小关系即为数组元素的大小关系。</mark></p>
<p>要定义的几个参数：</p>
<p>开始位置：<code>left = 0;</code>（数组下标索引从0开始）</p>
<p>结束位置：<code>right = nums.size() - 1;</code> </p>
<p>中间值：<code>mid = left + ((right - left) &gt;&gt; 1) </code> (位运算，可以防止数组越界现象出现)</p>
<h2 id="2-4-注意点"><a href="#2-4-注意点" class="headerlink" title="2.4 注意点"></a>2.4 注意点</h2><ul>
<li>区间的划分</li>
</ul>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 原因是此时mid的值一定不是我们寻找的，否则不会出现在这个循环，那么我们在移动的时候也可以不考虑这个值</span></span><br><span class="line"><span class="keyword">if</span> (nums[middle] &gt; target) &#123;</span><br><span class="line">                right = middle - <span class="number">1</span>; <span class="comment">// target 在左区间，所以[left, middle - 1]</span></span><br><span class="line">            &#125;</span><br></pre></td></tr></table></figure>

<ul>
<li>循环终止判断条件</li>
</ul>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">while</span> (left &lt;= right) <span class="comment">// 当left==right，区间[left, right]依然有效，所以用 &lt;=</span></span><br></pre></td></tr></table></figure>



<h2 id="2-5-完整代码"><a href="#2-5-完整代码" class="headerlink" title="2.5 完整代码"></a>2.5 完整代码</h2><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span> &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="type">int</span> <span class="title">search</span><span class="params">(vector&lt;<span class="type">int</span>&gt;&amp; nums, <span class="type">int</span> target)</span> </span>&#123;</span><br><span class="line">        <span class="type">int</span> left = <span class="number">0</span>; <span class="comment">//定义数组的左节点</span></span><br><span class="line">        <span class="type">int</span> right = nums.<span class="built_in">size</span>()<span class="number">-1</span>; <span class="comment">//定义数组的右节点</span></span><br><span class="line">        <span class="keyword">while</span>(left &lt;= right) &#123;</span><br><span class="line">                <span class="type">int</span> mid = left + (right - left) / <span class="number">2</span>; <span class="comment">//定义中间点，防止索引越界</span></span><br><span class="line">                <span class="keyword">if</span>(target &lt; nums[mid]) &#123;</span><br><span class="line">                    right = mid - <span class="number">1</span>; <span class="comment">// 目标值在左区间</span></span><br><span class="line">                &#125;</span><br><span class="line">                <span class="keyword">else</span> <span class="keyword">if</span>(target &gt; nums[mid]) &#123;</span><br><span class="line">                    left = mid + <span class="number">1</span>; <span class="comment">// 目标值在右区间</span></span><br><span class="line">                &#125;</span><br><span class="line">                <span class="keyword">else</span> <span class="keyword">if</span>(target == nums[mid]) &#123;</span><br><span class="line">                    <span class="keyword">return</span> mid;</span><br><span class="line">                &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"></span><br></pre></td></tr></table></figure>

<hr>
<h1 id="3-双指针法"><a href="#3-双指针法" class="headerlink" title="3. 双指针法"></a>3. 双指针法</h1><h2 id="相关题目-1"><a href="#相关题目-1" class="headerlink" title="相关题目"></a>相关题目</h2><ul>
<li>例题：</li>
</ul>
<p><a target="_blank" rel="noopener" href="https://leetcode.cn/problems/remove-element/">Problem 27.移除元素</a></p>
<ul>
<li>相关题目：</li>
</ul>
<p><a target="_blank" rel="noopener" href="https://leetcode.cn/problems/squares-of-a-sorted-array/">Problem 977.有序数组的平方</a></p>
<h2 id="3-1-使用条件"><a href="#3-1-使用条件" class="headerlink" title="3.1 使用条件"></a>3.1 使用条件</h2><p>需要双重遍历：需要实现先定位元素，再实现元素修改的题目，都可以用双指针法。</p>
<p>双指针法（快慢指针法）： <strong>通过一个快指针和慢指针<mark>在一个for循环下完成两个for循环</mark>的工作。</strong></p>
<p>定义快慢指针</p>
<ul>
<li>快指针：寻找新数组的元素 ，新数组就是不含有目标元素的数组</li>
<li>慢指针：指向<mark>更新</mark>新数组下标的位置</li>
</ul>
<h2 id="3-2-复杂度"><a href="#3-2-复杂度" class="headerlink" title="3.2 复杂度"></a>3.2 复杂度</h2><ul>
<li>时间复杂度：<code>O(n)</code></li>
<li>空间复杂度：<code>O(1)</code></li>
</ul>
<h2 id="3-3-主要思想"><a href="#3-3-主要思想" class="headerlink" title="3.3 主要思想"></a>3.3 主要思想</h2><p><code>fastIndex</code>指针用来寻找要<strong>删除</strong>的值，<code>slowIndex</code>指针用来定位要<strong>修改</strong>的值</p>
<p>在删除元素这道题目中，体现在<code>fastIndex</code>在一直在移动，而通过判断<code>if(nums[fastIndex] != val) </code>来控制是否替换，相当于核心思想是在<mark>原有的数组上替换了一个新的数组，这个数组元素所要满足的条件就是if判断的条件</mark>。</p>
<h2 id="3-4-注意点"><a href="#3-4-注意点" class="headerlink" title="3.4 注意点"></a>3.4 注意点</h2><p>用双指针移动删除元素可以使得时间复杂度下降，只需要一个循环遍历即可，一个指针用来寻找删除元素，另一个指针用来实现替换操作。 这里用for循环，不用while循环的原因是： for循环一般用于有终止条件，变量只有一个并且判断条件可以简单的用一个boolean表达式表现出来，而while循环主要用于迭代条件较为复杂，例如二分查找法的情况，左右节点都需要根据不同情况进行更新。 而在双指针中，fastIndex指针是无条件一直向前运行的，我们只需在循环体中控制slowIndex指针即可。</p>
<h2 id="3-5-代码实现"><a href="#3-5-代码实现" class="headerlink" title="3.5 代码实现"></a>3.5 代码实现</h2><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span> &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="type">int</span> <span class="title">removeElement</span><span class="params">(vector&lt;<span class="type">int</span>&gt;&amp; nums, <span class="type">int</span> val)</span> </span>&#123;</span><br><span class="line">        <span class="comment">//双指针删除元素 fast指针用于搜索，slow指针用于替换值</span></span><br><span class="line">        <span class="type">int</span> slowIndex = <span class="number">0</span>;</span><br><span class="line">        <span class="comment">//结束条件，搜索指针搜索完成。</span></span><br><span class="line">        <span class="keyword">for</span>(<span class="type">int</span> fastIndex = <span class="number">0</span>; fastIndex &lt; nums.<span class="built_in">size</span>(); fastIndex++ ) &#123;</span><br><span class="line">            <span class="keyword">if</span>(nums[fastIndex] != val) &#123;</span><br><span class="line">                nums[slowIndex ++] = nums[fastIndex];</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> slowIndex;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>



<p><font size=4><strong>双指针Pro（相向双指针）：</strong></font></p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span> &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="type">int</span> <span class="title">removeElement</span><span class="params">(vector&lt;<span class="type">int</span>&gt;&amp; nums, <span class="type">int</span> val)</span> </span>&#123;</span><br><span class="line">        <span class="type">int</span> leftIndex = <span class="number">0</span>;</span><br><span class="line">        <span class="type">int</span> rightIndex = nums.<span class="built_in">size</span>() - <span class="number">1</span>;</span><br><span class="line">        <span class="keyword">while</span> (leftIndex &lt;= rightIndex) &#123;</span><br><span class="line">            <span class="comment">// 找左边等于val的元素</span></span><br><span class="line">            <span class="keyword">while</span> (leftIndex &lt;= rightIndex &amp;&amp; nums[leftIndex] != val)&#123;</span><br><span class="line">                leftIndex++;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="comment">// 找右边不等于val的元素</span></span><br><span class="line">            <span class="keyword">while</span> (leftIndex &lt;= rightIndex &amp;&amp; nums[rightIndex] == val) &#123;</span><br><span class="line">                rightIndex-- ;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="comment">// 将右边不等于val的元素覆盖左边等于val的元素</span></span><br><span class="line">            <span class="keyword">if</span> (leftIndex &lt; rightIndex) &#123;</span><br><span class="line">                nums[leftIndex++] = nums[rightIndex--];</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> leftIndex;   <span class="comment">// leftIndex一定指向了最终数组末尾的下一个元素，原因是因为有几个val就代表被中断了几次，此时只有单向运动，长度就会缩减</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>



<hr>
<h1 id="4-滑动窗口"><a href="#4-滑动窗口" class="headerlink" title="4. 滑动窗口"></a>4. 滑动窗口</h1><h2 id="相关题目-2"><a href="#相关题目-2" class="headerlink" title="相关题目"></a>相关题目</h2><ul>
<li>例题：</li>
</ul>
<p><a target="_blank" rel="noopener" href="https://leetcode.cn/problems/minimum-size-subarray-sum/">Problem 209.长度最小的子数组</a></p>
<ul>
<li>相关题目：</li>
</ul>
<h2 id="4-1-使用条件"><a href="#4-1-使用条件" class="headerlink" title="4.1 使用条件"></a>4.1 使用条件</h2><p>数组中满足条件的最小子数组。一般求解需要经过两个步骤，首先需要先判断出有哪些满足条件的情况<strong>存在</strong>。之后再去这些满足条件存在中求解<strong>最优</strong>。</p>
<p>一般会出现如下条件需要去定义：</p>
<ul>
<li>滑动窗口的起始点（可以理解为快指针）</li>
<li>滑动窗口的终止点（可以理解为慢指针）</li>
<li>滑动窗口内条件的表示：例如最大值，元素相等之类的</li>
</ul>
<h2 id="4-2-复杂度"><a href="#4-2-复杂度" class="headerlink" title="4.2 复杂度"></a>4.2 复杂度</h2><ul>
<li>时间复杂度：<code>O(n)</code></li>
</ul>
<blockquote>
<p>主要是看每一个元素被操作的次数，每个元素在滑动窗后进来操作一次，出去操作一次，每个元素都是被操作两次，所以时间复杂度是 2 × n 也就是O(n)。</p>
</blockquote>
<ul>
<li>空间复杂度：<code>O(1)</code></li>
</ul>
<h2 id="4-3-主要思想"><a href="#4-3-主要思想" class="headerlink" title="4.3 主要思想"></a>4.3 主要思想</h2><p>时间复杂度的优化其实可以简略的看成循环的优化，而循环优化的最主要思想之一就是<mark>能否对相关项进行合并</mark>。换而言之就是变量之间能不能够相互解释。</p>
<p>对比暴力解法和滑动窗口能够发现其精妙之处：</p>
<ul>
<li>暴力解法：判断满足条件的子数组存在（一层遍历） &#x3D;&#x3D;&#x3D;&gt; 子数组内判断是否最优（存在遍历中的遍历）&#x3D;&#x3D;&#x3D;&gt; 比较</li>
<li>滑动窗口：移动终止点去判断是否存在 &#x3D;&#x3D;&#x3D;&gt; 移动起始点去求最优</li>
</ul>
<p>这时候我们会发现，其实滑动窗口用了条件这个东西同时判断了两个值， 而暴力解法则是在数组内部又进行了一个数组的判断，所以我们其实可以用两个点窗口大小去表示条件的时候，这样做就相当于实现了循环次数的减少。</p>
<h2 id="4-4-注意点"><a href="#4-4-注意点" class="headerlink" title="4.4 注意点"></a>4.4 注意点</h2><ol>
<li><p>求和的操作很巧妙，融合在一起表现在头指针移动会影响到数组和值，尾指针移动也能够影响到数组的和值。</p>
</li>
<li><p>数组最小长度的迭代更新，首先直接替换肯定不行，因为无法确定最后一个就是最小的。然后自己比自己求最小也不行，因为你需要一个0的初始值。所以在这里需要引入一个新的变量，result &#x3D; INT32_MAX。</p>
</li>
</ol>
<blockquote>
<p>INT32_MAX是一个常量，表示极大值，主要作用是有值时第一次比较时一定会被替换成result, 如果没有被比较到，那么最后返回结果用三元运算符返回0即可。</p>
</blockquote>
<h2 id="4-5-代码实现"><a href="#4-5-代码实现" class="headerlink" title="4.5 代码实现"></a>4.5 代码实现</h2><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span> &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="type">int</span> <span class="title">minSubArrayLen</span><span class="params">(<span class="type">int</span> target, vector&lt;<span class="type">int</span>&gt;&amp; nums)</span> </span>&#123;</span><br><span class="line">        <span class="comment">//因为其要变化两个量：最小数组的开始值，数组的长度，所以可能需要两次for循环来找到答案</span></span><br><span class="line">        <span class="comment">//滑动窗口法:将结果看成是变化，找到大于target的数组，之后不断缩小，贪心算法？</span></span><br><span class="line">        <span class="type">int</span> fastIndex = <span class="number">0</span>, slowIndex = <span class="number">0</span>, sum = <span class="number">0</span>, length = <span class="number">0</span>, result = INT32_MAX;</span><br><span class="line">        <span class="comment">//小于等于是考虑末值的条件</span></span><br><span class="line">        <span class="keyword">for</span>(;fastIndex &lt; nums.<span class="built_in">size</span>(); fastIndex++) &#123;</span><br><span class="line">            <span class="comment">//求和放在和</span></span><br><span class="line">            sum += nums[fastIndex];</span><br><span class="line">            <span class="keyword">while</span>(sum &gt;= target) &#123;</span><br><span class="line">                length = (fastIndex - slowIndex + <span class="number">1</span>) ;</span><br><span class="line">                result = result &gt; length ? length : result;</span><br><span class="line">                sum -= nums[slowIndex];</span><br><span class="line">                slowIndex++;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> result == INT32_MAX ? <span class="number">0</span> : result;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"></span><br></pre></td></tr></table></figure>



<hr>
<h1 id="5-螺旋矩阵"><a href="#5-螺旋矩阵" class="headerlink" title="5. 螺旋矩阵"></a>5. 螺旋矩阵</h1><h2 id="相关题目-3"><a href="#相关题目-3" class="headerlink" title="相关题目"></a>相关题目</h2><p><a target="_blank" rel="noopener" href="https://leetcode.cn/problems/spiral-matrix-ii/">Problem 59.螺旋矩阵</a></p>
<h2 id="5-1-使用条件"><a href="#5-1-使用条件" class="headerlink" title="5.1 使用条件"></a>5.1 使用条件</h2><p>题目告诉你要用螺旋矩阵，没有什么特别算法的意思，更多的是体现了一种对语言的运用和流程的表述</p>
<h2 id="5-2-复杂度"><a href="#5-2-复杂度" class="headerlink" title="5.2 复杂度"></a>5.2 复杂度</h2><h2 id="5-3-主要思想"><a href="#5-3-主要思想" class="headerlink" title="5.3 主要思想"></a>5.3 主要思想</h2><p>模拟顺时针画矩阵的过程:</p>
<ul>
<li>填充上行从左到右</li>
<li>填充右列从上到下</li>
<li>填充下行从右到左</li>
<li>填充左列从下到上</li>
</ul>
<p>由外向内一圈一圈这么画下去。</p>
<h2 id="5-4-注意点"><a href="#5-4-注意点" class="headerlink" title="5.4 注意点"></a>5.4 注意点</h2><p>开闭区间的判断</p>
<h2 id="5-5-代码实现"><a href="#5-5-代码实现" class="headerlink" title="5.5 代码实现"></a>5.5 代码实现</h2><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span> &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    vector&lt;vector&lt;<span class="type">int</span>&gt;&gt; <span class="built_in">generateMatrix</span>(<span class="type">int</span> n) &#123;</span><br><span class="line">        vector&lt;vector&lt;<span class="type">int</span>&gt;&gt; <span class="built_in">res</span>(n, <span class="built_in">vector</span>&lt;<span class="type">int</span>&gt;(n, <span class="number">0</span>)); <span class="comment">// 使用vector定义一个二维数组</span></span><br><span class="line">        <span class="type">int</span> startx = <span class="number">0</span>, starty = <span class="number">0</span>; <span class="comment">// 定义每循环一个圈的起始位置</span></span><br><span class="line">        <span class="type">int</span> loop = n / <span class="number">2</span>; <span class="comment">// 每个圈循环几次，例如n为奇数3，那么loop = 1 只是循环一圈，矩阵中间的值需要单独处理</span></span><br><span class="line">        <span class="type">int</span> mid = n / <span class="number">2</span>; <span class="comment">// 矩阵中间的位置，例如：n为3， 中间的位置就是(1，1)，n为5，中间位置为(2, 2)</span></span><br><span class="line">        <span class="type">int</span> count = <span class="number">1</span>; <span class="comment">// 用来给矩阵中每一个空格赋值</span></span><br><span class="line">        <span class="type">int</span> offset = <span class="number">1</span>; <span class="comment">// 需要控制每一条边遍历的长度，每次循环右边界收缩一位</span></span><br><span class="line">        <span class="type">int</span> i,j;</span><br><span class="line">        <span class="keyword">while</span> (loop --) &#123;</span><br><span class="line">            i = startx;</span><br><span class="line">            j = starty;</span><br><span class="line"></span><br><span class="line">            <span class="comment">// 下面开始的四个for就是模拟转了一圈</span></span><br><span class="line">            <span class="comment">// 模拟填充上行从左到右(左闭右开)</span></span><br><span class="line">            <span class="keyword">for</span> (j = starty; j &lt; n - offset; j++) &#123;</span><br><span class="line">                res[startx][j] = count++;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="comment">// 模拟填充右列从上到下(左闭右开)</span></span><br><span class="line">            <span class="keyword">for</span> (i = startx; i &lt; n - offset; i++) &#123;</span><br><span class="line">                res[i][j] = count++;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="comment">// 模拟填充下行从右到左(左闭右开)</span></span><br><span class="line">            <span class="keyword">for</span> (; j &gt; starty; j--) &#123;</span><br><span class="line">                res[i][j] = count++;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="comment">// 模拟填充左列从下到上(左闭右开)</span></span><br><span class="line">            <span class="keyword">for</span> (; i &gt; startx; i--) &#123;</span><br><span class="line">                res[i][j] = count++;</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            <span class="comment">// 第二圈开始的时候，起始位置要各自加1， 例如：第一圈起始位置是(0, 0)，第二圈起始位置是(1, 1)</span></span><br><span class="line">            startx++;</span><br><span class="line">            starty++;</span><br><span class="line"></span><br><span class="line">            <span class="comment">// offset 控制每一圈里每一条边遍历的长度</span></span><br><span class="line">            offset += <span class="number">1</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 如果n为奇数的话，需要单独给矩阵最中间的位置赋值</span></span><br><span class="line">        <span class="keyword">if</span> (n % <span class="number">2</span>) &#123;</span><br><span class="line">            res[mid][mid] = count;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> res;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>


      
    </div>

    
    
    
      <footer class="post-footer">
        <div class="post-eof"></div>
      </footer>
  </article>
  
  
  

      
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://daorongxing.gitee.io/post/16107/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="Daorong Xing">
      <meta itemprop="description" content="这是我的个人博客，记录计算机学习之路！">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="邢道荣的个人博客">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          
            <a href="/post/16107/" class="post-title-link" itemprop="url">Hello World</a>
        </h2>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>

              <time title="创建时间：2022-11-18 11:15:02" itemprop="dateCreated datePublished" datetime="2022-11-18T11:15:02+08:00">2022-11-18</time>
            </span>
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="far fa-calendar-check"></i>
                </span>
                <span class="post-meta-item-text">更新于</span>
                <time title="修改时间：2022-11-30 16:09:27" itemprop="dateModified" datetime="2022-11-30T16:09:27+08:00">2022-11-30</time>
              </span>

          <br>
            <span class="post-meta-item" title="本文字数">
              <span class="post-meta-item-icon">
                <i class="far fa-file-word"></i>
              </span>
                <span class="post-meta-item-text">本文字数：</span>
              <span>367</span>
            </span>
            <span class="post-meta-item" title="阅读时长">
              <span class="post-meta-item-icon">
                <i class="far fa-clock"></i>
              </span>
                <span class="post-meta-item-text">阅读时长 &asymp;</span>
              <span>1 分钟</span>
            </span>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
          <p>Welcome to <a target="_blank" rel="noopener" href="https://hexo.io/">Hexo</a>! This is your very first post. Check <a target="_blank" rel="noopener" href="https://hexo.io/docs/">documentation</a> for more info. If you get any problems when using Hexo, you can find the answer in <a target="_blank" rel="noopener" href="https://hexo.io/docs/troubleshooting.html">troubleshooting</a> or you can ask me on <a target="_blank" rel="noopener" href="https://github.com/hexojs/hexo/issues">GitHub</a>.</p>
<h2 id="Quick-Start"><a href="#Quick-Start" class="headerlink" title="Quick Start"></a>Quick Start</h2><h3 id="Create-a-new-post"><a href="#Create-a-new-post" class="headerlink" title="Create a new post"></a>Create a new post</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo new <span class="string">&quot;My New Post&quot;</span></span><br></pre></td></tr></table></figure>

<p>More info: <a target="_blank" rel="noopener" href="https://hexo.io/docs/writing.html">Writing</a></p>
<h3 id="Run-server"><a href="#Run-server" class="headerlink" title="Run server"></a>Run server</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo server</span><br></pre></td></tr></table></figure>

<p>More info: <a target="_blank" rel="noopener" href="https://hexo.io/docs/server.html">Server</a></p>
<h3 id="Generate-static-files"><a href="#Generate-static-files" class="headerlink" title="Generate static files"></a>Generate static files</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo generate</span><br></pre></td></tr></table></figure>

<p>More info: <a target="_blank" rel="noopener" href="https://hexo.io/docs/generating.html">Generating</a></p>
<h3 id="Deploy-to-remote-sites"><a href="#Deploy-to-remote-sites" class="headerlink" title="Deploy to remote sites"></a>Deploy to remote sites</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo deploy</span><br></pre></td></tr></table></figure>

<p>More info: <a target="_blank" rel="noopener" href="https://hexo.io/docs/one-command-deployment.html">Deployment</a></p>

      
    </div>

    
    
    
      <footer class="post-footer">
        <div class="post-eof"></div>
      </footer>
  </article>
  
  
  


  



          </div>
          

<script>
  window.addEventListener('tabs:register', () => {
    let { activeClass } = CONFIG.comments;
    if (CONFIG.comments.storage) {
      activeClass = localStorage.getItem('comments_active') || activeClass;
    }
    if (activeClass) {
      let activeTab = document.querySelector(`a[href="#comment-${activeClass}"]`);
      if (activeTab) {
        activeTab.click();
      }
    }
  });
  if (CONFIG.comments.storage) {
    window.addEventListener('tabs:click', event => {
      if (!event.target.matches('.tabs-comment .tab-content .tab-pane')) return;
      let commentClass = event.target.classList[1];
      localStorage.setItem('comments_active', commentClass);
    });
  }
</script>

        </div>
          
  
  <div class="toggle sidebar-toggle">
    <span class="toggle-line toggle-line-first"></span>
    <span class="toggle-line toggle-line-middle"></span>
    <span class="toggle-line toggle-line-last"></span>
  </div>

  <aside class="sidebar">
    <div class="sidebar-inner">

      <ul class="sidebar-nav motion-element">
        <li class="sidebar-nav-toc">
          文章目录
        </li>
        <li class="sidebar-nav-overview">
          站点概览
        </li>
      </ul>

      <!--noindex-->
      <div class="post-toc-wrap sidebar-panel">
      </div>
      <!--/noindex-->

      <div class="site-overview-wrap sidebar-panel">
        <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
    <img class="site-author-image" itemprop="image" alt="Daorong Xing"
      src="/images/avatar.gif">
  <p class="site-author-name" itemprop="name">Daorong Xing</p>
  <div class="site-description" itemprop="description">这是我的个人博客，记录计算机学习之路！</div>
</div>
<div class="site-state-wrap motion-element">
  <nav class="site-state">
      <div class="site-state-item site-state-posts">
          <a href="/archives/">
        
          <span class="site-state-item-count">10</span>
          <span class="site-state-item-name">日志</span>
        </a>
      </div>
      <div class="site-state-item site-state-categories">
            <a href="/categories/">
          
        <span class="site-state-item-count">4</span>
        <span class="site-state-item-name">分类</span></a>
      </div>
      <div class="site-state-item site-state-tags">
            <a href="/tags/">
          
        <span class="site-state-item-count">5</span>
        <span class="site-state-item-name">标签</span></a>
      </div>
  </nav>
</div>
  <div class="links-of-author motion-element">
      <span class="links-of-author-item">
        <a href="https://github.com/yourname" title="GitHub → https:&#x2F;&#x2F;github.com&#x2F;yourname" rel="noopener" target="_blank"><i class="fab fa-github fa-fw"></i></a>
      </span>
      <span class="links-of-author-item">
        <a href="/2630168952@qq.com" title="E-Mail → 2630168952@qq.com"><i class="fa fa-envelope fa-fw"></i></a>
      </span>
      <span class="links-of-author-item">
        <a href="/2630168952@qq.com" title="QQ → 2630168952@qq.com"><i class="fa fa-qq fa-fw"></i></a>
      </span>
  </div>



<script type="text/javascript" charset="utf-8" src="/js/tagcloud.js"></script>
<script type="text/javascript" charset="utf-8" src="/js/tagcanvas.js"></script>
<div class="widget-wrap">
    <h3 class="widget-title">标签云</h3>
    <div id="myCanvasContainer" class="widget tagcloud">
        <canvas width="250" height="250" id="resCanvas" style="width=100%">
            <ul class="tag-list" itemprop="keywords"><li class="tag-list-item"><a class="tag-list-link" href="/tags/JVM/" rel="tag">JVM</a><span class="tag-list-count">4</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Spring/" rel="tag">Spring</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E6%8C%87%E9%92%88/" rel="tag">指针</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E7%AE%97%E6%B3%95/" rel="tag">算法</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E7%BB%93%E6%9E%84%E4%BD%93/" rel="tag">结构体</a><span class="tag-list-count">1</span></li></ul>
        </canvas>
    </div>
</div>


      </div>
        <div class="back-to-top motion-element">
          <i class="fa fa-arrow-up"></i>
          <span>0%</span>
        </div>

    </div>
  </aside>
  <div id="sidebar-dimmer"></div>


      </div>
    </main>

    <footer class="footer">
      <div class="footer-inner">
        

        

<div class="copyright">
  
  &copy; 
  <span itemprop="copyrightYear">2022</span>
  <span class="with-love">
    <i class="fa fa-heart"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">Daorong Xing</span>
    <span class="post-meta-divider">|</span>
    <span class="post-meta-item-icon">
      <i class="fa fa-chart-area"></i>
    </span>
      <span class="post-meta-item-text">站点总字数：</span>
    <span title="站点总字数">91k</span>
</div>

        








      </div>
    </footer>
  </div>

  
  <script src="/lib/anime.min.js"></script>
  <script src="//cdn.jsdelivr.net/npm/jquery@3/dist/jquery.min.js"></script>
  <script src="//cdn.jsdelivr.net/gh/fancyapps/fancybox@3/dist/jquery.fancybox.min.js"></script>
  <script src="//cdn.jsdelivr.net/npm/pangu@4/dist/browser/pangu.min.js"></script>
  <script src="/lib/velocity/velocity.min.js"></script>
  <script src="/lib/velocity/velocity.ui.min.js"></script>

<script src="/js/utils.js"></script>

<script src="/js/motion.js"></script>


<script src="/js/schemes/pisces.js"></script>


<script src="/js/next-boot.js"></script>




  




  
<script src="/js/local-search.js"></script>













  

  

</body>
</html>
